题解:P12555 [UOI 2024] AND Array
Solution
高一的时候我们教练往 CSP 模拟赛里扔了一个这样的题:
给定一个长度为
10^5 的,值域在[0,2^{18}) 中的数组a 。每次给定(x,v) ,求出最小的i \ge x ,使得a_i \text{ and } v=0 。
当时就整出了一个这样的做法:从后往前扫描
然后有两种做法:插入
发现这样询问和修改必须有一个是
回到这道题,我们现将
每次询问,我们先找到一个
显然我们找到的
所以说,我们这时候有
最短解,跑得也挺快。
#include<bits/stdc++.h>
#define ll long long
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=1e5+10,MAXM=(1<<20)+10;
int n,b,a[MAXN],vis[MAXM],l;
ll sum,ans[MAXN];
int main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>b,l=min(b,14);
ffor(i,1,n) cin>>a[i];
roff(i,n,1) {
if(!a[i]) sum+=i;
else {
int dt=(1<<l)-1-(a[i]&((1<<l)-1)),ot=(((a[i]>>l)+1)<<l)-1;
for(int s=dt;s;s=(s-1)&dt) vis[ot-s]=i;
vis[ot]=i;
}
ans[i]=b*sum;
ffor(j,0,b-1) {
int ot=(1<<b)-1-(1<<j);
while(1) {
int x=(ot>>l)<<l,y=ot-x,nxt=n+1;
for(int s=x;s;s=(s-1)&x) if(vis[s+y]) nxt=min(nxt,vis[s+y]);
if(vis[y]) nxt=min(nxt,vis[y]);
if(nxt==n+1) break ;
ans[i]+=nxt,ot-=a[nxt];
}
}
}
ffor(i,1,n) cout<<ans[i]<<' ';
return 0;
}