[平衡规划]JZOJ 4616 二进制的世界
分析
我们可以考虑朴素暴力,f[x]表示数为x的个数
那么插入是$O(1)$的,而查找是$O(2^16)$的
这里可以采用平衡规划的技巧
设f[i][j]表示前8位为i的数与后8位为j的数进行运算,后8位的最大值
g[i][j]则表示方案数
那么插入时,a为数前8位,b为后8位,则得:f[a][j]=max{f[a][j],j opt b}
查询时,得:ans=max{f[i][b]|((a opt i)<<8)}
这样两个操作就被平衡成$O(2^8)$级别的了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; const int N=256; int f[N][N],g[N][N]; int n,type; char opt[10]; int main() { freopen("binary.in","r",stdin); freopen("binary.out","w",stdout); scanf("%d%s%d",&n,opt,&type); memset(f,-1,sizeof f); for (int i=1,a;i<=n;i++) { scanf("%d",&a); int a1=a>>8,a2=a&((1<<8)-1); int mx=0,ans=0; if (opt[0]=='a') { for (int j=0;j<(1<<8);j++) if (f[j][a2]>=0&&(((j&a1)<<8)|f[j][a2])>=mx) { if ((((j&a1)<<8)|f[j][a2])>mx) ans=0; mx=((j&a1)<<8)|f[j][a2];ans+=g[j][a2]; } for (int j=0;j<(1<<8);j++) if ((j&a2)>=f[a1][j]) { if (f[a1][j]<(j&a2)) g[a1][j]=0; f[a1][j]=j&a2;g[a1][j]++; } } if (opt[0]=='o') { for (int j=0;j<(1<<8);j++) if ((((j|a1)<<8)|f[j][a2])>=mx) { if ((((j|a1)<<8)|f[j][a2])>mx) ans=0; mx=((j|a1)<<8)|f[j][a2];ans+=g[j][a2]; } for (int j=0;j<(1<<8);j++) if ((j|a2)>=f[a1][j]) { if (f[a1][j]<(j|a2)) g[a1][j]=0; f[a1][j]=j|a2;g[a1][j]++; } } if (opt[0]=='x') { for (int j=0;j<(1<<8);j++) if ((((j^a1)<<8)|f[j][a2])>=mx) { if ((((j^a1)<<8)|f[j][a2])>mx) ans=0; mx=((j^a1)<<8)|f[j][a2];ans+=g[j][a2]; } for (int j=0;j<(1<<8);j++) if ((j^a2)>=f[a1][j]) { if (f[a1][j]<(j^a2)) g[a1][j]=0; f[a1][j]=j^a2;g[a1][j]++; } } if (i>1) { printf("%d",mx); if (type) printf(" %d\n",ans); else printf("\n"); } } }
在日渐沉没的世界里,我发现了你。