看大雪如何衰老的 / 我的眼睛如何融化
算了。
S>a<M
能做的操作:一个数变成 \(0\),一个前缀 \([0,i]\) 变成 \(i+1\)。
求 \(f(S)\):枚举一个要填满的前缀,后面每种数只保留一个,必然存在最优解形式为这样。倒着扫前缀,对于前缀的每个位置 \(i\) 限定过程中至少要得到 \(x\) 个 \(i\),如果 \(cnt_i\geq x\) 就把多的变成 \(0\);否则 \(x\to 2x-cnt_i\)。最后检查 \(0\) 够不够。这个判定的本质是增加了两个操作的独立性。
求 \(f(S)=k\):转而求 \(f(S)\geq k\)。 根据上文可以看出,可以被判定成功的前缀也是一个前缀,也就是说 \([0,i]\) 判定成功必有 \([0,i-1]\) 判定成功。钦定最大的前缀 \([0,i]\) 使得填满这段前缀恰好 \(=k\),对 \(>i\) 的位置限制了不同位置的个数,而对前缀正着 dp,记录前 \(i\) 个位置在 \(S\) 里出现了 \(j\) 次,且根据上述判定,到 \(i\) 时有 \(c\) 个 \(0\),以及判定时的 \(x\),状态看似 \(O(n^4)\),实则 \(ix\leq n\),状态数为 \(O(n^3\ln n)\)。然后如果不存在 \([0,i]\) 这段前缀满足恰好 \(=k\),意味着一开始的颜色数就 \(>k\),加一下这部分贡献即可。
子集和
Cow Circle 告诉我们循环卷积很难做除法,那道题的做法是作 \(x^z\to x\) 的换元。
\(l_1=r_1,l_2=r_2\):猫树分治,每个分治区间要求干掉一个点的信息,缺一分治,需要加入 \(O(n\log^2n)\) 次物品。询问时只需要求单点值所以可以 \(O(qm)\)。
暴力:猫树分治,当两个区间不同时完全位于分治区间一侧时,一定有一侧只有一个区间,可以删掉那一侧。这样询问是 \(O(mq\log n)\)。
正解:将询问变成 \(O(1)\) 个前后缀询问,可以去 \(\log\)。
Path XOR on MST
看似强制在线,但实际这个问题是半在线的(端点未被加密),所以最终做法是分治。
考虑如何求出 MST。CDQ 分治,处理到 \([l,r]\) 时将 \(1\sim l-1\) 的边分为三种:一定在最小生成树上,一定不在,可能在。一定在的直接加入并查集,对于可能在的边,先将 \([l,r]\) 的边设为 \(-\infty\) 做一遍最小生成树,此时仍然加入的边是一定会存在于最小生成树的;再设为 \(+\infty\) 做一遍,此时没加入的边一定是不在的。这样做之后能保证状态不确定的边不超过 \(r-l+1\) 条。需要可撤销并查集。
考虑对于一个最小生成树,预先加入 \((a_i,b_i,0)\) 的边,再加入生成树上的边,这样只需要求出环空间的一组基。这个问题相当于,合并时若位于同一个集合内,则将环的大小插入线性基。带权可撤销并查集维护到根的距离即可。时间复杂度 \(2\log\)。线性基也要支持撤销。
算了。
struct base{
int a[31],stk[maxn],tp;
void clear(){
tp=0;
for(int i=0;i<30;i++)a[i]=0;
}
void ins(int x){
for(int i=29;~i;i--)if(x>>i&1){
if(!a[i]){
a[i]=x;
stk[++tp]=i;
break;
}
x^=a[i];
}
if(!x)stk[++tp]=-1;
}
int qmax(){
int res=0;
for(int i=29;~i;i--)if(!(res>>i&1))res^=a[i];
return res;
}
void pop(){
assert(tp);
if(stk[tp]!=-1)a[stk[tp]]=0;
tp--;
}
}b;
struct uset{
int to[maxn],v[maxn],sz[maxn],tp;
std::array<int,3>stk[maxn];
void clear(){
tp=0;
for(int i=1;i<=n;i++)to[i]=i,v[i]=0,sz[i]=1;
}
int go(int x){
if(to[x]==x)return x;
return go(to[x]);
}
int we(int x){
if(to[x]==x)return 0;
return v[x]^we(to[x]);
}
void merge(int x,int y,int w){
int fx=go(x),fy=go(y),wx=we(x),wy=we(y);
if(fx==fy){
b.ins(wx^wy^w);
stk[++tp]={-1,-1,wx^wy^w};
return;
}
if(sz[fx]<sz[fy]){
stk[++tp]={fx,fy,v[fx]};
to[fx]=fy;
sz[fy]+=sz[fx];
v[fx]=(wx^wy^w);
}else{
stk[++tp]={fy,fx,v[fy]};
to[fy]=fx;
sz[fx]+=sz[fy];
v[fy]=(wx^wy^w);
}
}
void pop(){
assert(tp);
if(stk[tp][0]==-1)b.pop();
else{
int x=stk[tp][0],y=stk[tp][1],w=stk[tp][2];
to[x]=x;
sz[y]-=sz[x];
v[x]=w;
}
tp--;
}
}d;
struct uset1{
int to[maxn],sz[maxn],tp;
pii stk[maxn];
void clear(){
tp=0;
for(int i=1;i<=n;i++)to[i]=i,sz[i]=1;
}
int go(int x){
if(to[x]==x)return x;
return go(to[x]);
}
bool merge(int x,int y){
x=go(x),y=go(y);
if(x==y)return stk[++tp]={-1,-1},0;
if(sz[x]>sz[y])std::swap(x,y);
stk[++tp]={x,y};
to[x]=y;sz[y]+=sz[x];
return 1;
}
void pop(){
assert(tp);
if(stk[tp].fi==-1)return tp--,void();
to[stk[tp].fi]=stk[tp].fi;
sz[stk[tp].se]-=sz[stk[tp].fi];
tp--;
}
}f;
int cmp(int x,int y){
if(w[x]==w[y])return x<y;
return w[x]<w[y];
}
void solve(int l,int r,vint S){//S:可能在最小生成树上的边
// debug("[%lld,%lld]\n",l,r);
vint T,K,nT;//可能在最小生成树上的边 一定在最小生成树上的边
int cnt=0;
std::sort(all(S),cmp);
for(int i=l;i<=r;i++)f.merge(u[i],v[i]);
for(int i:S)
if(f.merge(u[i],v[i]))/*debug("%lld must be installed\n",i),*/K.eb(i);
else T.eb(i);
for(int i=1;i<=r-l+1+SZ(S);i++)f.pop();
for(int i:K)f.merge(u[i],v[i]),d.merge(u[i],v[i],c[i]),cnt++;
for(int i:T)if(f.merge(u[i],v[i]))nT.eb(i);
for(int i=1;i<=SZ(T);i++)f.pop();
T.swap(nT);
if(l==r){
if(l!=m)decode(w[l],c[l]);
T.eb(l);
std::sort(all(T),cmp);
for(int i:T)if(f.merge(u[i],v[i]))d.merge(u[i],v[i],c[i]),cnt++;
ans=b.qmax();
println(ans);
for(int i=1;i<=SZ(T)+SZ(K);i++)f.pop();
for(int i=1;i<=cnt;i++)d.pop();
return;
}
int mid=(l+r)>>1;
solve(l,mid,T);
for(int i=l;i<=mid;i++)T.eb(i);
solve(mid+1,r,T);
for(int i=1;i<=cnt;i++)f.pop(),d.pop();
}
Dyads of Hanoi
找到最大不对的圆盘 \(k\) 后操作有两种 pattern,\(x\to y\) 或者 \(x\to z\to y\),由于不可能两次经过一个圆盘所以只有这两种。
\(d(X,x)\):要将 \(X\) 全部移到 \(x\) 上,将最大的没在 \(x\) 上的记为 \(k\),位于 \(y\),则为 \(d(<k,z)+2^{k-1}\)。如果选择 \(y\to z\to x\) 一定更劣,因为归纳可以说明 \(d(X,x)\) 的上界是 \(2^n\)。这样最短方案唯一。
所以原问题的两种 pattern 对应的答案就是 \(d(X_{<k},z)+1+d(Y_{<k},z)\) 和 \(d(X_{<k},y)+2^{k-1}+1+d(Y_{<k},x)\)。只需判定这两个值是否相同。继续研究 \(k\) 减小的过程的话那么就是 \(x,y,z\) 发生改变同时加上一个 \(2\) 的幂次。从小往大数位 dp 钦定一下 \(x,y,z\) 即可。具体来说 \(f_{i,x_0,y_0,x_1,y_1,j}\) 代表对 \([1,i)\) 赋值使得 \(d(X_{\leq i},x_0)+d(Y_{\leq i},y_0)-d(X_{\leq i},x_1)-d(Y_{\leq i},y_1)+j\times 2^{i}=0\) 的方案数,其中 \(-1\leq j\leq 1\),最后就是枚举一个 \(k\) 然后利用 \(f_{k-1,x_0,y_0,x_1,y_1,1}\) 即可。
写了一点话又删了,算了。

浙公网安备 33010602011771号