BZOJ4762: 最小集合

    xiaoxiao2021-03-25  76

    感谢度教。。。

    转化条件1 : 使Or 其他不变

    S|S|1T1 |S|使Or

    然后考虑暴力 g[i][j][k]i Orj Ork

    转移时并不好处理

    考虑改一下状态 f[i][j][k]i Orj Ork g[0][0][1023]=1 则转移很方便 有 f[i][j][k]>g[i+1][j|a[i+1]][l] Sl && lT && lT S=k&a[i+1] T=S|(a[i+1]&j) fg 发现可以直接利用 f 进行转移 f[i 1][j|a[i 1]][S] =f[i][j][k] f[i+1][j|a[i+1]][T]=f[i][j][k] 时间复杂度 O(n410)

    发现最后的答案 f[n][1023][0] 只和 g[0][0][1023] 有关 所以我们可以直接令 f[0][0][0]=1 做出来答案不变

    这有什么好呢? 我们会发现所有有用的集合k皆为j的子集

    然后就变成了 O(n310)

    #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> using namespace std; int f[2][1024][1024]; const int Mod=1e9+7; inline void Up(int&a,int b){a+=b;a>=Mod?a-=Mod:(a<0?a+=Mod:a);} int main() { int n; scanf("%d",&n); int now=1,last=0; f[last][0][0]=1; for(int i=1;i<=n;i++,now^=1,last^=1) { int p,t; scanf("%d",&p); for(int j=0;j<1024;j++) for(int k=j;;k=(--k)&j) { f[now][j][k]=f[last][j][k]; if(!k)break; } p=1023-(t=p); for(int j=0;j<1024;j++) if((j|p)^j) for(int k=j;;k=(--k)&j) { Up(f[now][j|p][k&t],f[last][j][k]),Up(f[now][j|p][(k&t)|(p^(p&j))],-f[last][j][k]); if(!k)break; } } cout<<f[last][1023][0]; return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-39813.html

    最新回复(0)