专栏文章
题解:P14473 [集训队互测 2025] 少年汹涌
P14473题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min5mg6n
- 此快照首次捕获于
- 2025/12/01 20:57 3 个月前
- 此快照最后确认于
- 2025/12/01 20:57 3 个月前
一个 做法,但是好像跑得很快。(认为 和 同阶)
很小,所以考虑用一些东西来简化变化的过程。
注意到如果不考虑后 位,每次变化最多让前面的位 。设 表示 , 除掉后 位的 ,让 除掉后 位的值增加 所需的次数; 表示此时 后 位的值。转移是不难的,可以 预处理出来。注意为了保证能正确处理 ,只有 时可以用这些值来更新 。
以下用 表示 。
如果 ,考虑先让 。可以先把 变成 的一段前缀,再把后面的位补上。而前面部分可以不断让 。这样只需要变化 次。后面的部分暴力跳即可。
时即要求出树的大小。先给 从小到大排序,然后依次加入,然后更新当前树的大小。算大小时先把所有 的 跳成 ,注意到此时本质不同的 只能有 个。把 和所有 一起往上跳。先跳 ,等 lowbit 固定了再从高位到低位枚举即可,过程与普通倍增类似。
所以时间复杂度为 。
CPP#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,w[65],g[64][64][64];
ll L,a[60005],f[64][64][64],b[65];
bitset<64> vis;
int mov(ll &sf,int r,ll x,ll y){
while(x&&x+(x&-x)<=y)
sf+=f[__lg(x&-x)][__builtin_popcountll(x)][r],r=g[__lg(x&-x)][__builtin_popcountll(x)][r],x+=x&-x;
if((x&y)!=x) cout<<x<<' '<<y<<'\n';
y^=x;
for(int i=56;~i;i--)
if(y>>i&1)
sf+=f[i][__builtin_popcountll(x)][r],r=g[i][__builtin_popcountll(x)][r],x+=(1ll<<i);
return r;
}
ll lca(ll x,ll r,ll mn){
ll now=0;int ct=0;
for(int i=0;i<64;i++)
if(vis[i])
b[ct++]=i;
while(now<mn){
int lb=(x?__lg(x&-x):0),pc=__builtin_popcountll(x),vl=g[lb][pc][r];
bool flg=0;
for(int i=0;i<ct;i++)
if(g[lb][pc][b[i]]==vl){
flg=1;
break;
}
if(!flg){
now+=f[lb][pc][r],r=vl;
for(int i=0;i<ct;i++) b[i]=g[lb][pc][b[i]];
x+=(1ll<<lb);
}
else{
for(lb--;~lb;lb--){
pc=__builtin_popcountll(x),vl=g[lb][pc][r];
bool flg=0;
for(int i=0;i<ct;i++)
if(g[lb][pc][b[i]]==vl){
flg=1;
break;
}
if(!flg){
now+=f[lb][pc][r],r=vl;
for(int i=0;i<ct;i++) b[i]=g[lb][pc][b[i]];
x+=(1ll<<lb);
}
}
bitset<64> vs=0;
r+=(x<<6);
for(int i=0;i<ct;i++) b[i]+=(x<<6);
for(int i=0;i<ct;i++)
while(1){
vs[b[i]&63]=1,b[i]+=w[__builtin_popcountll(b[i])];
if((b[i]>>6)>x) break;
}
while(!vs[r&63]&&(r>>6)==x)
now++,r+=w[__builtin_popcountll(r)];
break;
}
}
return now;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>L;
for(int i=1;i<63;i++) cin>>w[i];
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for(int k=0;k<57;k++)
for(int j=56;~j;j--)
for(int i=63;~i;i--){
if(k) f[k][j][i]=f[k-1][j][i]+f[k-1][j+1][g[k-1][j][i]],g[k][j][i]=g[k-1][j+1][g[k-1][j][i]];
else{
int pc=__builtin_popcount(i)+j;
if(i+w[pc]>63) f[k][j][i]=1,g[k][j][i]=(i+w[pc]&63);
else f[k][j][i]=f[k][j][i+w[pc]]+1,g[k][j][i]=g[k][j][i+w[pc]];
}
}
ll ans=0;
for(int i=1;i<=n;i++){
ll rs=0;
int r=mov(rs,a[i]&63,a[i]>>6,L>>6);
ll x=((L>>6)<<6)+r;
while(x<=L) x+=w[__builtin_popcountll(x)],rs++;
rs=min(rs,lca(a[i]>>6,a[i]&63,rs));
ans+=rs,vis[a[i]&63]=1;
if(i==n) break;
bitset<64> nv=0;
for(int j=0;j<64;j++)
if(vis[j])
nv[mov(rs,j,a[i]>>6,a[i+1]>>6)]=1;
vis=nv;
}
cout<<ans<<'\n';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...