4261. 孤独的照片 - AcWing题库
所需知识:贡献法
整体思路:首先想到暴力枚举所有区间,判断每个区间内是否有一种牛的数量是一只(提前用前缀和存放每个位置及以前的牛的数量)
C++代码:(过不了)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int n = 500000 + 5;
int A[n], B[n];
int ans;
int main()
{
int N;
cin >> N;
for (int i = 1; i <= N; i++) {
char x;
cin >> x;
if (x == 'G')
A[i] = A[i - 1] + 1;
else
A[i] = A[i - 1];
if (x == 'H')
B[i] = B[i - 1] + 1;
else
B[i] = B[i - 1];
}
for (int i = 0; i <= N; i++) {
for (int j = i + 3; j <= N; j++) {
if ((A[j] - A[i] == 1) || (B[j] - B[i] == 1))
ans++;
}
}
cout << ans;
return 0;
}
但显然这个方法不太可行,枚举区间的复杂度就有n2了,不管怎么优化,始终逃不过1要枚举区间的这件事,难道没有其他办法了吗?No!当然有!
贡献法:由于区间数量过大,我们没办法枚举区间,换个角度思考,一张孤独的照片里面只能有一只同品种的牛,所以把旁边全是不同种类牛的牛的数量找出来就可以算出来所要求的区间数了,
一头孤独的牛对应的区间数量res=sl [i] *sr [i] +max(0,sl [i]-1)+max(0,sr [i]-1);
sl [i] 表示第i头牛左边与它不一样的牛的数量 ,sr [i] 表示第i头牛右边与它不一样的牛的数量,当两边取的时候,区间数为sl [i] *sr [i]当只考虑左边时,区间数为max(0,sl [i]-1),因为只考虑左边,当作右边没有,所以左边需要多拿出来一个与它不同的,剩余的数量就是sl [i] -1了,取max是因为,sl [i]可能为0,就是旁边没有与之不同的,区间的数量就是0,倘若不与0取max,那么就是在原有区间数量-1,显然不对,区间数只可能加,不可能减,右边max(0,sr [i]-1)同理;
#include <iostream>
#include <cstring>
#include <algorithm>
typedef long long ll;
using namespace std;
const int n = 500000+5;
int sl[n],sr[n];
ll ans;
char cow[n];
int sg,sh;
int main()
{
int N;
cin>>N;
for (int i = 1; i <= N; i ++ )
cin>>cow[i];
for (int i = 1; i <= N; i ++ ){
if(cow[i]=='G') {sl[i]=sh,sg++,sh=0;}
else {sl[i]=sg,sh++,sg=0;}
}
sh=0,sg=0;
for (int i = N; i >=1; i -- ){
if(cow[i]=='G') {sr[i]=sh,sg++,sh=0;}
else {sr[i]=sg,sh++,sg=0;}
}
for (int i = 1; i <= N; i ++ ){
ans+=1LL*sl[i]*sr[i]+max(0,sr[i]-1)+max(0,sl[i]-1);
}
cout<<ans;
return 0;
}