1 条题解
-
0
自动搬运
来自洛谷,原作者为

Purslane
AFO搬运于
2025-08-24 23:16:26,当前版本为作者最后更新于2025-05-28 15:35:33,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Solution
高一的时候我们教练往 CSP 模拟赛里扔了一个这样的题:
给定一个长度为 的,值域在 中的数组 。每次给定 ,求出最小的 ,使得 。
当时就整出了一个这样的做法:从后往前扫描 。查询的时候将 取反,即要求 。
然后有两种做法:插入 的时候,暴力扫描其所有超集;或者询问 的时候,查询其所有子集。
发现这样询问和修改必须有一个是 有一个是 。考虑根号分治,对于后 位做一种算法,对于前 位做另一种算法。即在 的复杂度内解决了这个题。
回到这道题,我们现将 的位置剔除。直接做 次询问。
每次询问,我们先找到一个 使得 。然后 。不断重复此过程。
显然我们找到的 一定是递增的,符合题目要求。而在 次操作后此过程一定会终止。
所以说,我们这时候有 次修改, 次查询。那么很容易平衡到 。
最短解,跑得也挺快。
#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; }
- 1
信息
- ID
- 12322
- 时间
- 7000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者