AcWing 2868.子串分值

首先上报一下自己暴力做的,可能也就能过50%得数据,后面显然是超时了。

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<sstream>
#include<map>
#include<limits.h>
#include<set>
#define MAX 100010
#define _for(i,a,b) for(int i=a;i<(b);i++)
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
LL n, m, counts, num;
string s;
map<char, int>maps;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> s;
    counts += s.size();
    num = 2;
    for (int i = 0; i < s.size()-(num-1); i++) {
        string buf = s.substr(i,num);
        maps.clear();
        for (int j = 0; j < buf.size(); j++) {
            maps[buf[j]]++;
        }
        for (int j = 0; j < buf.size(); j++) {
            if (maps[buf[j]] == 1)
                counts++;
        }
        if (i == s.size() - num)
        {
            i = -1;
            num++;
        }
    }
    cout << counts << endl;
    return 0;
}

这里解释一下自己的做法:

首先看到这些字符串的子集都是连续子集,所以我们可以用滑动窗口的方法进行做,可以规定每次滑动窗口的大小,再在这个滑动窗口里面统计不同的字母。

这里统计字母的时候用到了map容器,用来记录每个字母的数目。在后面的判断当中,我们可以在个数是1的情况下更新当前子集不同字符的个数。这样一直进行下去就行了。时间复杂度最好是

O(N2),所以并不能过数据。

然后就学到了一种方法叫做贡献法。这里运用贡献的话也就是说当我们碰到一个字母之后,我们看看除了没有这个字母之外的子集我们能贡献多少个子集。

比如,a....a....a,其中.都是不为a的字符,那么从中间那个a开始(我们只考虑有一个a的情况)这样我们就会有(6-1)*(11-6)种子集,这样的话我们每个位置都可以这样枚举,然后算出贡献的子集数。

那么,就按照这个思路进行编写程序就行了。

注意:数据范围上我们需要在最后结果上用long long类型,这样才能保证数据不超过int。

上代码:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<cmath> 
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<sstream>
#include<map>
#include<limits.h>
#include<set>
#define MAX 100010
#define _for(i,a,b) for(int i=a;i<(b);i++)
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
LL n, m, counts, num;
char s[MAX];
int l[MAX], r[MAX], p[MAX];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    cin >> s + 1;
    int n = strlen(s + 1);
    _for(i, 1, n+1) {
        int tmp = s[i] - 'a';//字母代表的数字
        l[i] = p[tmp];
        p[tmp] = i;
    }
    _for(i, 0, 26)p[i] = n + 1;
    for (int i = n; i; i--) {
        int tmp = s[i] - 'a';
        r[i] = p[tmp];
        p[tmp] = i;
    }
    for (int i = 1; i <= n; i++)
        counts += (LL)(i - l[i]) * (r[i] - i);
    cout << counts << endl;
    return 0;
}

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值