Educational Codeforces Round 93 (Rated for Div. 2)补题

比赛链接

C

题意:
问一串数字中有多少子串的长度等于串中所有数字之和
思路:
不会做,我只能想两重循环,一个数一个数的处理,时间复杂度1010,超时。
其实可以不用一个数一个数的处理,只需要用一个map。
因为如果要满足题目中的条件的话,子串中 s u m / l e n = 1 sum/len=1 sum/len=1,即每个数都是1。我们从前往后遍历把每一个数减去1求前缀和。如果某一段的总和为0,就证明这一段是满足的。例如统计到目前为止sum=-4,经过一段子串后又sum=-4,说明中间一段为0,我们就可以统计对于-4来说,中间有几段为0,假设有n段,则ans+=n*(n-1)/2

#include 
 
using namespace std;
 
int t, n;
string s;
 
map<int, int> mp;
 
int main()
{
    ios::sync_with_stdio(false);
    cin >> t;
    while (t--)
    {
        cin >> n;
        cin >> s;
        int sum = 0;
        for (int i = 0; i < n; i++)
        {
            sum += (s[i] - '0' - 1);
            mp[sum]++;
        }
        sum = 0;
        long long ans = mp[0];
        for (int i = 0; i < n; i++)
        {
            sum += (s[i] - '0' - 1);
            mp[sum]--;
            ans += mp[sum];
        }
        cout << ans << '\n';
        mp.clear();
    }
    return 0;
}

还有一种做法是牺牲了内存来换取时间
注意:这里可以用memset(m,0,sizeof(m))来替换但会大大提高时间
在这里插入图片描述

 for(int i = 0 ; i < n ; ++ i)
        {
            now += s[i] - '0';
            m[now - i - 1 + MID] --;
        }
#include
using namespace std;
typedef long long LL;
int m[2010101];
int MID = 1000000;
char s[101010];
int main()
{
     ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    freopen("E:\\in.txt","r",stdin);
    int T;
    scanf("%d", &T);
    m[MID] ++;
    while(T --)
    {
        int n;
        scanf("%d", &n);
        scanf("%s", s);
        LL ans = 0, now = 0;
        for(int i = 0 ; i < n ; ++ i)
        {
            now += s[i] - '0';
            ans += m[now - i - 1 + MID];
            m[now - i - 1 + MID] ++;
        }
        printf("%lld\n", ans);
        now = 0;
        for(int i = 0 ; i < n ; ++ i)
        {
            now += s[i] - '0';
            m[now - i - 1 + MID] --;
        }
    }
    return 0;
}

你可能感兴趣的:(div2)