场上过不去的简单题
\(\tt\bf{I. AT\_abc370\_f}\)
首先套路的破换成链,然后二分答案 \(p\)。
对于每一个二分的答案 \(p\),考虑先二分出 \(f_{i,0}\) 表示 \(i\) 之后第一个满足 \(\sum\limits_{j=i}^{f_{i,0}} a_j\ge p\) 的 \(f_{i,0}\),然后倍增的设 \(f_{i,j}\) 表示 \(i\) 之后满足 \(2^j\) 次上述条件的下标为 \(f_{i,j}\)。特殊的若不可以满足则令 \(f_{i,j}=-1\)。
然后考虑枚举起点,直接暴力倍增计算出 \(k\) 次操作之后的答案即可。时间复杂度为 \(O(n\log^2n)\)。代码有点混乱。
const int N=400100,mod=998244353;
int a[N],s[N],n,k,now,nxt[N][20],res;
bool chk(int p){
memset(nxt,-1,sizeof nxt);
F(i,1,n+n){
int l=i,r=i+n-1,best=-2;
r=min(r,n+n);
while(l<=r){
int mid=l+r>>1;
if(s[mid]-s[i-1]>=p)best=mid,r=mid-1;
else l=mid+1;
}
nxt[i][0]=best+1;
}
nxt[n+n+1][0]=n+n+1;
F(i,1,19)
F(j,1,n+n+1)
if(~nxt[j][i-1])
nxt[j][i]=nxt[nxt[j][i-1]][i-1];
// F(i,1,n+n)
// cout<<i<<": "<<nxt[i][0]<<' '<<nxt[i][1]<<" qwq\n";
int cnt=0;
F(i,1,n){
int x=i;
G(j,19,0)
if(k>>j&1){
x=nxt[x][j];
if(x==-1||x>i+n)break;
}
if(x!=-1&&x<=i+n)
++cnt;
}
if(cnt)
res=n-cnt;
return !!cnt;
}
signed main(){
cin>>n>>k;
F(i,1,n)cin>>a[i],s[i]=s[i-1]+a[i];
F(i,1,n)a[i+n]=a[i],s[i+n]=s[i+n-1]+a[i];
int l=1,r=s[n],best=-1;
while(l<=r){
int mid=l+r>>1;
if(chk(mid))best=mid,l=mid+1;
else r=mid-1;
}
cout<<best<<' '<<res<<'\n';
}
本文来自博客园,作者:yhbqwq,转载请注明原文链接:https://www.cnblogs.com/yhbqwq/p/18404602,谢谢QwQ