AGC061E Increment or XOR
本来想写一个有关思维过程的题解,写出来却成了这样一个怪胎,大家当个乐子看。
最近回顾了一下 Picks loves segment tree IX,然后终于会做这题了,其实两题在思维上有很大的相似之处。
核心思想是划分阶段的问题。
分析一下 \(+1\) 的操作,应该怎么考虑:
看作 bitxor 一段 \(1\):这样需要记录末尾 \(1\) 的连续个数(最低的一个 \(0\) 在哪里),不太好做。
转换一下思路,\(+1\) 会把最后一段 \(1\) 用 \(0\) 清空,接下来的过程从一段 \(0\) 开始。状态里记录末尾 \(0\) 的个数。(这跟上面链接那题差不多)
状态记录末尾 \(0\) 的个数有什么好处?因为这是适应 \(+1\) 操作的子结构,某次 \(+1\) 后会把 \([0,i]\) 清空,形成了一个子问题(从 \(0\) 到某个状态),初始状态就只要考虑 \(S/0\) 两种。
并且,在 \(+1\) 操作冲破第 \(i\) 位前,第 \(i\) 位都不受影响,这意味着在状态中额外记录 每个 \(Y_i\) 被 XOR 了奇数还是偶数次,第 \(i\) 位就确定了。
这体现了 \(+1\) 操作的单调性:在冲到第 \(i\) 位前第 \(i\) 位都不受影响,冲到第 \(i\) 位后起点统一变成 \([0,i]\) 全是 \(0\) 的状态。
根据单调性,可以设计从低位 dp 转移到高位的状态。下面分析一下变化的阶段。
对于最下面的若干位,整个过程是从 \(S\to 0\to T\) 的。
初始状态有两种,\(0\sim i-1\) 位从 \(S\) 开始和从 \(0\) 开始。
结束状态有两种,\(0\sim i-1\) 位和 \(T\) 相同且不向 \(i\) 进位;\(0\sim i-1\) 位清成全 \(0\) 并往上进一位。
设 \(f(i,0/1,0/1,msk)\) 表示只考虑最低的 \(0\sim i-1\) 位(即 \(+1\) 时不能影响更上面的位),起点的两个情况(\(0/1\) 表示 \(S/0\) 开始),终点的两个情况(\(0/1\) 表示 \(T\) 结束并不进位 / \(0\) 结束并进位),在这个变化过程中 \(msk\) 集合的 \(Y_i\) 被 XOR 了奇数次。
从 \(f(i)\) 转移到 \(f(i+1)\):
转移 1:如果(进位/不进位了之后)第 \(i\) 位是匹配的,可直接转移到 \(f(i+1,j_0,j_1,msk)\)。
转移 2:考虑进行了新的进位操作的转移。
- 先调用 \(f(i,j_0,1,msk)\) 操作,条件是从 \(j_0\) 开始,这个操作完后第 \(i\) 位是 \(1\)(即进位只进到第 \(i\) 位,不能影响上面的位)。
- 然后调用若干次 \(f(i,1,1,msk)\) 进位操作,条件是这个操作完后第 \(i\) 位是 \(1\)(即进位只进到第 \(i\) 位,不能影响上面的位)。
- 最后调用一次 \(f(i,1,j_1,msk)\) 操作,条件是进到第 \(i\) 位时符合 \(j_1\) 的要求。
转移写出来就是 \(f(i,j_0,1,msk_0)+f(i,1,1,msk_1)+f(i,1,1,msk_2)+...+f(i,1,j_1,msk_l) \to f(i+1,j_0,j_1,\oplus\ msk)\)。
容易发现这是一个最短路的形式,可以用 dijkstra 的方式,每次从 dp 数组中取出最小的未用过的一个,转移到其他所有的,一次 dp 复杂度就是 \(2^{2n}\)。
初始状态不需要任何一位匹配,就是 \(f(0,j,0,msk)=\sum_{x\in msk}C_x,f(0,j,1,msk)=\sum_{x\in msk}C_x+A\)。
最终答案就是 \(\min(f_{40,0,0,msk})\),于是总复杂度 \(O(2^{2n}\log V)\)。
#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
#define int long long
using namespace std;
#define maxn 800005
#define inf 0x3f3f3f3f3f3f3f3f
int n,S,T,A,mxs;
int x[66],c[66],sx[666],sc[666];
int f[42][2][2][260],g[260];
bool vis[260];
signed main()
{
n=read(),S=read(),T=read(),A=read(),mxs=1<<n;
For(i,0,n-1)x[i]=read(),c[i]=read();
For(s,0,mxs-1)
For(i,0,n-1)
if(s>>i&1)sx[s]^=x[i],sc[s]+=c[i];
memset(f,63,sizeof f);
For(s,0,mxs-1)
For(i,0,1) For(j,0,1) f[0][i][j][s]=sc[s]+A*j;
For(i,0,39){
// from a to b
For(j0,0,1)For(j1,0,1){
int a=j0?0:(S>>i&1);
int b=j1?1:(T>>i&1);
For(s,0,mxs-1)
if((sx[s]>>i&1)==(a^b))
f[i+1][j0][j1][s]=f[i][j0][j1][s];
}
For(j0,0,1){
int a=j0?0:(S>>i&1);
memset(g,63,sizeof g);
memset(vis,0,sizeof vis);
For(s,0,mxs-1)
if((sx[s]>>i&1)==a) g[s]=f[i][j0][1][s];
while(1){
int mn=inf,u=-1;
For(s,0,mxs-1)
if(!vis[s] && g[s]<mn)mn=g[s],u=s;
if(u==-1)break;
vis[u]=1;
For(s,0,mxs-1)
if((sx[s]>>i&1)==1)
g[s^u]=min(g[s^u],g[u]+f[i][1][1][s]);
For(j1,0,1){
int b=j1?1:(T>>i&1);
For(s,0,mxs-1)
if((sx[s]>>i&1)==(b^1))
f[i+1][j0][j1][u^s]=min(g[u]+f[i][1][j1][s],f[i+1][j0][j1][u^s]);
}
}
}
}
int res=inf;
For(i,0,mxs-1)res=min(res,f[40][0][0][i]);
if(res==inf)puts("-1");
else cout<<res;
return 0;
}

浙公网安备 33010602011771号