G - Gangsta

题意:给定一个长度为n的01串,记f(l,r) 为出现区间[l,r]最多次字符的出现次数,求和sigma 1<=i<=j<=n f(j,i)

思路:
先考虑f(l,r)怎么求,设x为出现0的次数,y为出现1的次数
f(l,r)=max(x,y) =( x+y+|x-y| )/2
显然对于01串,x+y为区间长度len

关于len的求和:显然每个长度为i的区间总个数为(n-i+1) , 那么为 sigma求和 1<=i<=n ix(n-i+1)

关于ixi的求和公式:n(n+1)(2n+1)/6

关于|x-y|的求和,|x-y|的值是区间0和1的个数的差值

不妨令数组值为0的位置权值为-1,值为1的位置权值为1

那么|x-y|=|pre[r]-pre[l-1]|,即0<=l<r<=n sigma求和 |pre[r]-pre[l]|

由于对于这种二元关系而言,改变次序不会改变二元组的双方与对数以及结果的绝对值,因此直接将pre排序

对于每一个值,算贡献:设当前pre的位置为i,那么 +的贡献共有i个 , -的贡献共有n-i个,因此它的贡献为(2i-n)xpre_i

求和即可

void solve(){
    int n;cin>>n;
    string s;cin>>s;
    s=" "+s;
    vector<int>pre(n+1);
    rep(i,1,n){
        if(s[i]=='0')pre[i]=-1;
        else pre[i]=1;
    }
    rep(i,1,n){
        pre[i]+=pre[i-1];
    }
    sort(pre.begin(),pre.end());
    int ans=0;
    rep(i,0,n){
        ans+=(2*i-n)*pre[i];
    }
    ans+=n*(n+1)*(n+2)/6;
    cout<<(ans>>1)<<endl;
}
posted @ 2025-09-02 21:10  Marinaco  阅读(8)  评论(0)    收藏  举报
//雪花飘落效果