AcWing-孤独的照片

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;
}

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值