P1131拯救大兵瑞恩
题目
题意从(1,1)出发走到(n,m),途中有墙有门有钥匙,问最短几步走到右下角。
思路利用状态压缩,用二进制位表示第几种钥匙是否持有,利用BFS爆搜,再开一个数组储存状态来记忆化剪枝
实现方法有很多种,可以利用邻接表建边,可以直接利用Next数组表示下一个位置,邻接表利用空间换取了时间,表示墙和门时如果不用邻接表,则需要用map
P175电路维修
题目
题意如图所示,旋转最少的电线使得左面的电源和发光器相连、
思路考虑把所有电线已经相连的点设为边权为0,没有连接的,比如电线是主对角线,副对角线上的两个点就应该设为边权为1,最后跑一个从左上角到右下角的最短路径,将每一个点映射到一维数组中。
dijstla当然可以做,但是双端队列更高,因为这个图中只有边权为0和1的点,可以把优先队列的log(n)省掉,当遇到边权为0的点时就把点直接添加到队头,遇到边权为1的点放到队尾,并且判断能否更新当前点离起点的距离。
CODE123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113#include <bits/stdc++.h>#de ...
P341最优贸易
题目
题意n个城市,从1到n点,有有向边,也有无向边,每个城市都有宝石价格,从一个点买一个宝石,再在后面走的点卖出,问最多赚多少钱?
思路对每一个路径求一个前缀最小值和后缀最大值,对每一个点后缀减去前缀取最大值即是答案,细节就是,求后缀可以反建图,开一个rhead数组
CODE1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162#include <bits/stdc++.h>#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);using namespace std;const int MAXN=500000;const int INF=0x3f3f3f3f;struct node{ int to,next;}e[MAXN];queue<int> q;int head[MAXN],val[MAXN], ...
P342道路与航线
题目
题意给定t个点,r条道路,p条航线,和一个起点,道路可互相到达,航线只能单向到达,且航线的权值可能为负数,问从起点到各个点的最小距离是多少?若不可到达输出“NO PATH”
思路把所有道路相连的点组成联通块,给他们编上号,从起点所在的联通块往后跑一个拓扑排序,连通块内跑dijstla,松弛时发现松驰的点和当前点不在一个连通块内,则把更新的点所在的联通块入度-1,大致思路是这样,但是还是有许多细节问题
为什么一开始要加入入度为0的点?
因为要保证拓扑序列的进行。假设s所在块编号为a,a连向块c,块b连向块c,且块a块b不相连。此时,如果你不加入入度为0的点,那么b块就不会访问到,c的入度也就不会减到0,也就不会访问到。
判断无解为什么不写出==inf?
因为有坑1的存在。还是上面那个例子,再加2个条件:
块d->块b,块a与块d不相连。
d到b的路为负边权
此时显然应该块b、d里所有的点都是NOPATH,而且dis都为inf。但其实在用块d内的点更新块b时,会松弛成功,因为存在负边权。所以无解时不一定dis就为inf
对每一个连通块跑最短路时,不知道那个点作 ...
P340通信线路
340. 通信线路分层图做法建k+1层图,相邻两层图之间权值为0,代表免费升级,在一层图里面跑就去找最大值,最后的答案就是第k+1层的dis[n]也就是dis[(k+1)*n],注意的是这样的做法只有在边数大于k时成立,当全部边都可以免费升级时,会出现问题,还没有跑到最后一层图就到达终点了,这时就会往回跑,导致边权增加,就会出错,所以需要把层与层之间的终点连接起来,使它们可以免费互相到达
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071#include <bits/stdc++.h>#define debug freopen("in.txt","r",stdin); freopen("out.txt","w",stdout)#define ios ios::sync_with_st ...
ACM冷知识
__int128C++支持的最大数据类型就是longlong,再大就会爆掉,所以出现了_int128类型,默认gcc是不支持编译的,但是在各大OJ上是可以运行的,\_int128不支持cin、cout,所以需要自己写读入打印函数,也就是传统的快读快写
1234567891011121314151617181920212223242526272829303132#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; void read(__int128 &x){ int y=1;x=0; char c=getchar(); while(c<'0' || c>'9'){ if(c=='-') y=-1; c=getchar(); } while(c>='0' && c<='9'){ x= ...
2021ICPC训练赛
Early Orders
题意n个数从中找出一个包含1-k的字典序最小子串,注意子串可以断开,但是相对顺序不能变
题解求得是字典序最小的子串,用一个单调栈维护,从栈底到栈顶依次表示子串的从前到后,为什么用栈呢?考虑子串的先后性,必须先把后面的更新了才能更新前面的,如何维护栈呢?对于栈顶元素,从左往右遍历的过程中如果这个数字比栈顶数字小,而且右面还有栈顶数字,那就可以出栈,还有就是当栈内有一个元素了,这时就不能再往里面塞这个元素,搞一个标记数组标记栈中是否有这个元素
CODE123456789101112131415161718192021222324252627282930313233#include <bits/stdc++.h>#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0) using namespace std;const int MAXN=1e6;stack<int> st;bool vis[MAXN];int ans[MAXN],a[MAXN],pos[MAXN];int mai ...
2021牛客寒假算法基础集训营5
B 比武招亲(上)
题目大意给定n,m,每次从1-n中挑选出m个数,可以重复挑选,挑选出的数的贡献值等于排序后最大值减去最小值,挑选的序列不同当且仅当两个序列排序后不同,求所有可能的序列的总贡献值?
解法可以枚举贡献值,差值一共有n-1种,差值固定了,也就是在m-2个空位中随意放置[min,max]的数,这里有一个坑,也不是随便放的,因为要求排过序后序列不同,也就是放置要求是单调不减,于是可以把+1看成一个隔板,就是在m-2+1个隔板中放置d(差值)个隔板,可是隔板可以连续放置,所以放置一个隔板后空位就会增多!所以答案不是C(m-1,d),雨巨的想法NB,考虑每一个隔板的左面带有一个空位,那么所有的隔板放完后空位就增加到了m-1+d个,在这些空位中放进去d个隔板,这个时候隔板就不能连续放了,因为每一个隔板左面都带有一个空位,所以每一个隔板左面都必须至少有一个空位,那最左面也不能放了,所以空位变成了m-1+d-1,答案就变成了从m-2+d个空位中放置d个隔板,隔板不能连续放,C(m-2+d,d),到这里题目就做出来一大半了,组合数复杂度为O(n),这里的n和m都是1e5,所以每次都算一遍 ...
整数分块
整数分块可以以log(n)的时间复杂度内求出${\sum_{i=1}^n\lfloor n/i \rfloor}$
小G的约数
解法单纯求F(n)O(n)求出,现在求$\sum{i=1}^nF_i$,可以换种思路,从个体对整体的贡献下手,对于每一个约数求有这个约数的所有数数量,显然是n/i个,然后乘上i,那么问题就转化为了${\sum{i=1}^n\lfloor n/i \rfloor*i}$,很明显的整数分块模板,什么是整数分块,考虑n=10的时候n/i的表
i: 1 2 3 4 5 6 7 8 9 10
n/i: 10 5 3 2 2 1 1 1 1 1
发现数字呈从大到小块状分布,只要知道了一个块的左端和右端就能直接算出这个块的n/i的和,这里有一个结论:$N/i==N/i’时,i’的最大值:N/(N/i)$,i’也就是右端点,因此可以枚举每一段区间,n/i的所有数字中不同数字的数量不会超过2*sqrt(n)个,因此时复就是sqrt(n)
整数分块函数123456789ll get(ll x){ ll ret=0; for(ll i=1;i<=x; ...
bitset
bitset用途这个东西相当于一个bool数组,int是32位表示一个数,而这个32位表示32个数,每一位只能存1或者0,这就使得可以开的空间是int的32倍,时间复杂度为(位数)N/W(计算机常数一般为32),而访问其中某一位时间复杂度为O(1),这个的用处多用于数组开不下1e9以上的空间,用unordered_map插入时复O(logn)级别,就可以用bitset优化时间为O(1)
定义与初始化使用bitset类型需#include<bitset>
bitset类型在定义时就需要指定所占的空间,例如
1bitset<233>bit;
bitset类型可以用string和整数初始化(整数转化成对应的二进制)
123456789101112#include<iostream>#include<bitset>#include<cstring>using namespace std;int main(){ bitset<23>bit (string("11101001")); ...



