編輯字串:這題能評藍已經說明了洛谷的唐氏。
結論
找到兩個字串種連續的且可以移動的所有極大子區間,然後線性掃一遍,看這一位所處的子區間中有多少個 \(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;
}