2021-10-11 杂题选听
CF1427E Xum
离谱
设原数是 \(x\),把原数不断左移,最低位与最高位对齐,记为 \(y\)
由于 \(k=y\oplus x=x\cdot 2^t-2^t+x\),所以 \(k\) 与 \(x\) 互质
考虑 exgcd 搞出 \(ak+bx=1\),并设 \(a'\ge |a|,b'\ge |b|\),设 \(a'k+b'x=e\)
则 \((a'+a)k+(b'+b)x=e+1\)
那一异或就出 \(1\) 了
CF1340D Nastya and Time Machine
设 \(d\) 为最大度数,答案肯定不小于 \(d\)
考虑构造答案为 \(d\) 的方案,从任一点开始 dfs,若 \(u\rightarrow v\) 时时间是 \(t\),则 \(v\rightarrow u\) 也应是 \(t\)
当到达一个点时时间到了 \(d\),就要减少时间,减小到 \(d-deg_u\),即可整好在 \(t\) 回到父亲
CF1442D Sum
考虑最后一定是有若干个数组取满了,最多有一个数组取了一部分
考虑若有两个数组都只取了一部分,那么由于数组不降,则把其中一个往前一个个删并在另一个后面加会更优
那么如果没取完的是 \(i\),对于剩下取完了的数组就是不考虑物品 \(i\) 的背包
这个东西就是分治一下,把左边的物品全加进去再分治到右边,右边全加进去分治到左边
复杂度 \(O(nk\log n)\)
#define N 3006
int n,k;
long long f[N],ans[N][N];
int num[N];
long long sum[N];
std::vector<int>a[N];
inline void work(int l,int r){
if(l==r) return std::memcpy(ans[l],f,sizeof ans[l]),void();
int mid=(l+r)>>1;
long long *backup=new long long[N];
std::memcpy(backup,f,sizeof f);
for(int i=l;i<=mid;i++){
for(int j=k;j>=num[i];j--) f[j]=std::max(f[j],f[j-num[i]]+sum[i]);
}
work(mid+1,r);
std::memcpy(f,backup,sizeof f);
delete backup;
for(int i=mid+1;i<=r;i++){
for(int j=k;j>=num[i];j--) f[j]=std::max(f[j],f[j-num[i]]+sum[i]);
}
work(l,mid);
}
int main(){
n=read();k=read();
for(int i=1;i<=n;i++){
num[i]=read();
for(int j=0;j<num[i];j++) a[i].push_back(read()),sum[i]+=a[i][j];
}
work(1,n);
long long Ans=0;
for(int i=1;i<=n;i++){
Ans=std::max(Ans,ans[i][k]);
long long sum=0;
for(int s=a[i].size(),j=0;j<s&&j<k;j++){
sum+=a[i][j];
Ans=std::max(Ans,ans[i][k-j-1]+sum);
}
}
printf("%lld\n",Ans);
return 0;
}
CF1446C Xor Tree
考虑建出 trie 来在上面 dp 最多能拿多少个
叶子的 \(f_u=1\),若一个点有两个儿子,则如果两边都选了超过一个数,则肯定是自己子树内连没有跨过子树的边
所以有一子树最多选一个,\(f_u=\max(f_{ls},f_{rs})+1\)
CF1439B Graph Subset Problem
从度数最小的点开始删,删到最小点度数 \(k\) 时,则满足了条件 \(2\)
满足条件 \(1\) 的情况必然有 \(k\le \sqrt{m}\),那么删的时候若删的是一个 \(k-1\) 度的点就暴力判一下他和他相邻的所有点是否构成团
\(O(n\sqrt{m}\log n)\),用 unordered_map
就没 \(\log\) 了
P4007 小 Y 和恐怖的奴隶主
设 \((i,a,b,c)\) 表示进行了 \(i\) 此攻击,\(1,2,3\) 血随从分别由 \(a,b,c\) 个
然后有用状态大概 \(\tbinom{8+3}{3}=165\),矩阵就是 \(166\times 166\) 的,那么每次暴力矩乘就是 \(O(T166^3\log n)\) 了
对于多测,可以把矩阵的 \(2^i\) 次幂都预处理出来,每次拿向量乘 \(O(\log n)\) 个矩阵,就有 \(O(166^3\log n+T166^2\log n)\)
hdu6145 Arithmetic of Bomb II
维护数对 \((a,b,c)\) 表示 \(a+b\times c\)
那么有如下变化:
- 加入一个数字 \(d\),有 \((a,b,c\times 10+d)\)
- 加入一个加号,有 \((a+b\times c,1,0)\)
- 加入一个减号,有 \((a+b\times c,-1,0)\)
- 加入一个乘号,有 \((a,b\times c,0)\)
再维护一个 \(b\times c\),这些玩意都可以用矩乘表示出来,于是就对每个重复部分加速一下就行
直接硬分类讨论也行?
P4766 [CERC2014]Outer space invaders
如果想按照时间从前往后 dp,需要记录的信息非常多
那么可以区间 dp,设 \(f_{i,j}\) 是将左右端点都在 \([i,j]\) 里的人干掉需要的最小代价
设其中 \(d\) 最大的人是 \(id\),那么肯定要开炮距离为 \(d_{id}\) 的,于是枚举啥时候开:
P4350 [CERC2015]Export Estimate
对于权值的限制,离线并从大到小加边
\(0,2\) 度点被删掉,\(2\) 度点会使得边数减一
但若对于一个无弦的环,上面都是二度点,但是最后会剩下一个点和一条自环没删掉
所以:点数=总点数-\(0,2\) 度点数+无弦环数
边数=加了的边数-\(2\) 度点数+无弦环数
P4748 [CERC2017]Justified Jungle
枚举 \(n\) 的约数是小于 \(\sqrt{n}\) 的,所以考虑对于每个暴力枚举并 \(O(n)\) 判断
若点满足子树大小是 \(\dfrac{n}{k+1}\) 的倍数,就可以切他和他父亲的边,若这样的点有 \(k+1\) 个(有个是根)就是可以
P4750 [CERC2017]Lunar Landscape
坐标很小,所以对于正着的正方形直接暴力差分
对于斜着的,每个格子拆成四个小三角形,对这些三角形差分
处理完直接枚举格子暴力数
AGC052B Tree Edges XOR
离谱
考虑规定点权,使得每个边权等于两端点点权异或和,比如可以规定点权是到根路径的异或和
这样一次操作相当于交换点权,那么就比较新旧树的点权是否相等即可,但要枚举根(端点异或相等不一定要求两个端点必须相等),还有个排序所以是 \(O(n^2\log n)\) 的
考虑如何省去枚举根的过程,从 \(1\) 为根求出原树的数组若为 \(a\),则以 \(rt\) 为根求出来的就是每个 \(a_i\) 都异或上 \(a_{rt}\)
再记目标树点权数组为 \(b\),那么就是 \(a\) 全部异或上其中某一项要和 \(b\) 相等,那么把 \(a,b\) 中所有项异或起来,就是 \(n\) 个 \(a_{rt}\) 异或起来,\(n\) 是奇数所以就是 \(a_{rt}\) 的值
那么给 \(a\) 全异或上 \(a_{rt}\) 再判断就行了
COCI2018-2019 Final T4 TENIS
考虑平面上建出三排点,分别按照三个属性排名排序,同一个人不同行的三个点连边
这样会产生若干个竖着的分割线(不经过连出的边),每两个分割线中间的部分对应着竞赛图的一个强连通分量,只有最左边的那个部分可以获胜
于是线段树维护,把每个人最小排名到最大排名的区间,加上 \(1\),求最左边的 \(0\)
\(O(n\log n)\)
P5307 [COCI2019] Mobitel
\(\lceil\dfrac{n}{1}\rceil,\lceil\dfrac{n}{2}\rceil,\cdots,\lceil\dfrac{n}{n}\rceil\) 一共 \(O(\sqrt{n})\) 种取值
于是记录 \(f(i,j,k)\) 表示走到 \(i,j\),再乘 \(k\) 就超过 \(n\) 的方案数,共 \(O(rs\sqrt{n})\) 个
P7207 [COCI2019-2020#3] Sob
由于对于任意 \(n,m\) 都有解,若能将区间 \([n-k,n-1]\) 和 \([m,m+k-1]\) 匹配上,就能递归到子问题
设 \(k\) 是能使得 \(m+k-1\) 与 \(n-1\) 匹配上的最小的 \(k\),则有结论 \(n-k \sim n-1\) 和 \(m+k-1 \sim m\) 按顺序分别可以匹配
考虑 \(i\) 是所有 \(n-1\) 是 \(1\) 而 \(m\) 是 \(0\) 的位中的最高位,那么 \(k\) 增大的过程就是把后 \(i\) 位加到和 \(n-1\) 相同,再减回去仍然可以
COI 2020 Pastiri
考虑目前深度最大的那个点,守卫放在里他最近但深度最浅的位置
如果守卫放他子树里显然不优,而如果不是放在他到根的链上的某个点上,而是在这些点的子树中,由于子树里也不会有更深的,所以也不会更优
于是每个点到最近的需要被看守的点的最短距离直接多源 bfs 预处理
COI 2020 Semafor
先把前 \(k\) 位灯管的转化 dp 出来,再舍弃不是数字的状态,转移 \(\frac{n}{k}\) 次
后面的矩阵大小是 \(100\times 100\),有 \(O(100^3\log n)\)
但前面直接搞是 \(O((2^{10})^3\log k)\) 的,但发现改哪根灯管都是等价的,所以只拿 \(\operatorname{popcount}\) 转移就行,矩阵大小 \(11\times 11\)
AGC043B 123 Triangle
先把数都减一,然后只剩 \(0,1,2\),若有 \(1\),则答案为 \(0\) 或 \(1\),否则为 \(0\) 或 \(2\)
都划归乘只有 \(0,1\) 的问题(不存在 \(1\) 就除以二,然后放 \(\mod 2\) 意义下),然后差分变成异或,第 \(i\) 位被异或了 \(\tbinom{n-1}{i}\) 次
AGC044B Joker
先从边界开始做一遍最短路,然后每次把没了的点放回队列里继续跑最短路,类似spfa
最短路 \(dis\) 和是 \(O(n^3)\) 的,每次只有 \(dis\) 降低才会进队,所以复杂度就 \(O(n^3)\) 了
AGC045B 01 Unbalanced
考虑 \(1\) 是 \(1\),\(0\) 是 \(-1\),答案就是前缀和的极差
然后你枚举最大值,能填 \(1\) 的问号尽量填 \(1\),否则搞成 \(-1\),判断是否能的办法就是对于每个后缀,记录每个 ?
都是 \(-1\) 的时候这个后缀的前缀最大值,看他有没有超过枚举的这个最大值
这样就是 \(O(n^2)\) 了
考虑设所有问号都填 \(-1\) 的最大值为 \(s\),那么把一个负一变成正一,则若最大值加 \(2\),则最小值最多加 \(2\),不会更优
那么只拿 \(s\) 和 \(s+1\) 跑一边就 \(O(n)\) 了
AGC045C Range Set
设 \(A\ge B\)
逆着操作,每次把 \(A\) 个 \(0\) 或 \(B\) 个 \(1\) 替换成任意串,然后如果操作到有 \(A\) 个连续的 \(0\) 就一定合法了
于是可以把所有大于等于 \(B\) 的 \(1\) 全换成 \(0\),dp 设 \(f(i,j,0/1)\) 表示考虑到第 \(i\) 个,替换后 \(0\) 的连续个数是 \(j\),目前在填 \(0/1\) 的方案数
需要个前缀和优化
CF1458C Latin Square
设 \(a\) 行 \(b\) 列是 \(c\),那么记录 \(A_{a,b}=c,B_{a,c}=b,C_{b,c}=a\)
如果是移动操作,就是给下标打标记,如果是变成逆排列操作,就是交换一个下标和他的值,也就是再开一个变量记录现在应该用哪个数组
CF1444D Rectangular Polyline
如果 \(h\neq v\) 或者无法把水平、竖直分别分成两个长度和相同的组,则无解
否则任意背包出一组,给出构造:
先考虑向右下走,把竖直这从大到小放,水平的从小到大放,这样一定不会穿过最终组成图形的对角线
从右下再走回来按照类似方法,就不会和之前有交了