場上過不去的簡單題

yhbqwq發表於2024-09-09

\(\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';
}

相關文章