题解:P12555 [UOI 2024] AND Array
每次都要扫一个后缀,考虑直接倒着做。
考虑如何计算一个
考虑这个子问题具有不合法不优的性质:我们无需考虑从
考虑把刚刚那个问题形式化:我们寻找跳的位置本质上是在求子集
直接做可以做到
考虑我们现在是一边查询
直接分成两半可以做到
int n,b;
int a[N];
int f[25];
int dp[1<<13][1<<7];
ll ans[N];
ll sum0;
int bl;
il int getf(int msk){
int cu=msk&((1<<bl)-1);
int minn=1e9;
for(int j=cu;;j=(j-1)&cu){
minn=min(minn,dp[msk>>bl][j]);
if(!j) break;
}
return minn;
}
// #define Shun cute
int main(){
#ifdef Shun
freopen("P12555_6.in","r",stdin);
freopen("ext.out","w",stdout);
#endif
ios::sync_with_stdio(false);
cin>>n>>b;
fr1(i,1,n) cin>>a[i];
bl=min(b,7);
memset(dp,0x3f,sizeof dp);
fr2(i,n,1){
fr1(j,0,b-1){
if(!((a[i]>>j)&1)){
ll sum=i;
int msk=(1<<b)-1-a[i]-(1<<j);
int id;
while((id=getf(msk))<=n){
sum+=id;
msk-=a[id];
}
f[j]=sum+sum0;
}
}
fr1(j,0,b-1) ans[i]+=f[j];
if(a[i]){
int fix=a[i]&((1<<bl)-1);
int oth=(a[i]>>bl);
int msk=(1<<b-bl)-1-(a[i]>>bl);
for(int j=msk;;j=(j-1)&msk){
dp[j|oth][fix]=min(dp[j|oth][fix],i);
if(!j) break;
}
}
else sum0+=i;
}
fr1(i,1,n) cout<<ans[i]<<' ';
ET;
}
//ALL FOR Zhang Junhao.