Luogu P11361 NOIP2024 编辑字符串 题解 [ 蓝 ] [ 贪心 ]

编辑字符串:adhoc 贪心题。

结论

找到两个字符串种连续的且可以移动的所有极大子区间,然后线性扫一遍,看这一位所处的子区间中有多少个 \(0\)\(1\),两个都有 \(0\) 就先消 \(0\),否则如果两个都有 \(1\) 就把 \(1\) 消掉,就做完了。

时间 \(O(Tn)\)

证明

洛谷上有一种很妙的证明,借鉴一下。

这题的答案显然是:

\[n-\sum_{i=1}^{n}(a_i-b_i)^2=n-(\sum_{i=1}^{n}(a_i^2+b_i^2-2a_ib_i)) \]

\[=n-(\sum_{i=1}^{n}a_i^2+\sum_{i=1}^{n}b_i^2-\sum_{i=1}^{n}2a_ib_i) \]

\[=n-\sum_{i=1}^{n}a_i^2-\sum_{i=1}^{n}b_i^2+\sum_{i=1}^{n}2a_ib_i \]

显然 \(n\)\(\sum_{i=1}^{n}a_i^2\)\(\sum_{i=1}^{n}b_i^2\) 已经是定值,那么我们要最大化 \(\sum_{i=1}^{n}2a_ib_i\),就要把 \(a_i,b_i\) 先全部放 \(1\)

由于这题 \(0\)\(1\) 具有对称性,所以先全部放 \(0\) 也是对的。

代码

代码也不难写,考场上 10min 打完的,思路也就想了 10min,还包括手模样例的时间。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,cnta,cntb,bla[100005],blb[100005],tota[100005][2],totb[100005][2],ans;
bitset<100005>a,b,ta,tb;
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        char x;
        cin>>x;
        a[i]=(x-'0');
    }
    for(int i=1;i<=n;i++)
    {
        char x;
        cin>>x;
        b[i]=(x-'0');
    }
    cnta=0;
    for(int i=1;i<=n;i++)
    {
        char x;
        cin>>x;
        ta[i]=(x-'0');
        if(ta[i]!=ta[i-1]||ta[i]==0)cnta++;
        bla[i]=cnta;
    }
    cntb=0;
    for(int i=1;i<=n;i++)
    {
        char x;
        cin>>x;
        tb[i]=(x-'0');
        if(tb[i]!=tb[i-1]||tb[i]==0)cntb++;
        blb[i]=cntb;
    }
    memset(tota,0,sizeof(tota));
    memset(totb,0,sizeof(totb));
    for(int i=1;i<=n;i++)
    {
        tota[bla[i]][a[i]]++;
        totb[blb[i]][b[i]]++;
    }
    ans=0;
    for(int i=1;i<=n;i++)
    {
        if(tota[bla[i]][0]>0&&totb[blb[i]][0]>0)
        {
            ans++;
            tota[bla[i]][0]--;
            totb[blb[i]][0]--;
        }
        else if(tota[bla[i]][1]>0&&totb[blb[i]][1]>0)
        {
            ans++;
            tota[bla[i]][1]--;
            totb[blb[i]][1]--;
        }
    }
    cout<<ans<<'\n';
}
int main()
{
    freopen("edit.in","r",stdin);
    freopen("edit.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin>>t;
    while(t--)solve();
    return 0;
}
posted @ 2024-12-07 00:17  KS_Fszha  阅读(124)  评论(0)    收藏  举报