首页 > 其他分享 >Codeforces Round 962(div 3) E Decode(解码)

Codeforces Round 962(div 3) E Decode(解码)

时间:2024-07-29 22:28:20浏览次数:10  
标签:arr 前缀 962 int Codeforces Decode 测试用例 区间 include

题目链接 :https://codeforces.com/contest/1996/problem/E

题目描述:

为了获得你最喜欢的角色,你不惜一切代价,侵入了游戏的源代码。经过几天的努力,你终于找到了编码游戏 gacha 系统的二进制字符串。为了解码它,你必须首先解决以下问题。给你一个长度为n的二进制字符串s。对于每对整数(l,r) (1≤l≤r≤n),计算子字符串Sx,Sx+1,Sx+2,...,Sy中 0的数量等于1的数量的对数(x,y)(l≤x≤y≤r),输出所用可能的(l,r)模数10^9 + 7

输入

第一行包含 t ( 1≤t≤1000) — 测试用例的数量。每个测试用例包含一个二进制字符串 s( 1≤|s|≤2⋅105)。保证 s仅包含字符 0和 1。保证所有测试用例的 |s|之和不超过 2⋅10^5第一行包含 t ( 1≤t≤1000) — 测试用例的数量。每个测试用例包含一个二进制字符串 s( 1≤|s|≤2⋅10^5)。保证 s仅包含字符 0和 1。保证所有测试用例的 |s|之和不超过 2⋅10^5

输出

对于每个测试用例,输出一个整数,答案模 109+7 。

题目分析:

首先,题意让我们找满足0的数量等于1的数量的每一个子集,很容易想到暴力的做法是,直接枚举所有子集,判断子集是否满足要求。但是,这样做就需要四层循环,分别是先确定l和r,然后再在l和r区间找子集,也就是枚举x,y这就是这四层循环。直接用暴力肯定是过不了的,所有我们要另寻他发。这题有”三典“:
1.放眼整个字符串,把字符0看成-1,字符1看成1,方便算满足条件的区间

2.经过1操作处理后的数组的前缀和(存放在数组arr中)

3.改变思考的角度,不从l,r这个大区间找x,y这个小区间,直接找x,y,然后求x,y能在多少个l,r里面出现,也就是求x,y区间对答案的贡献

经过这三个操作,我们很容易得出,假如arr[y] == arr[x - 1]就代表x,y区间满足条件,然后算贡献,既然这个贡献是看x,y在多少个l,r区间里面出现,这个区间首先是得包含x,y吧,那么,x左边有几个数能选加一乘以y右边有几个数能选加一就是所有包含x,y的l,r区间,为啥要加一呢?因为左边的选择有选一个选两个,也有不选这个选项,所以要加一,用数学式子来讲,就是区间数为x * (s.size() - y + 1)(x从1开始)。从这里看问题已经简化一半了,只用求前缀和,然后枚举x,y算贡献就行,但是还是有两层循环去计算答案,这个还能简化。假设我们正在枚举x,y区间,从右往左算,y循环是外层,x是里层,假设字符串是01010101,那么前缀和就是-1,0,-1,0,-1,0,-1,0,假设y是倒数第二个数,也就是y == 7,arr[y] == -1。这个时候让x往左动,第一个满足的x,y区间是x == 6,arr[x - 1] == arr[y],贡献是7 * 6。然后第二个x是 x == 4,贡献7 * 4,第三个是x == 2,合并多项式7 * (6 + 4 + 2),也就是y等于7时所有满足条件的x的坐标之和。从右向左也是同理。然后,我们能用可以用x边从左向右遍历前缀和数组,边找这个区间之前符合要求的x坐标的和,我们可以用map<int,long long> m来存,在到某一前缀和值arr[y]的时候能访问y之前所有满足条件的x的和。然后更新答案ans += m[arr[y]] * (n - y + 1),更新后也要更新相应的满足条件的x坐标的和。这样只需要一层循环去计算贡献。

只有前缀和跟求贡献的TLE代码:


#include <iostream>
#include <algorithm>
#include <string>
#define ll long long
using namespace std;
 
const int N = 200010;
int arr[N];
constexpr int P = 1e9 + 7;
 
void solve()
{
    string s;
    cin >> s;
 
    int len = s.size();
    for (int i = 0; i < len; i++)
    {
        if (s[i] == '0')
        {
            arr[i + 1] = -1;
        }
        else if (s[i] == '1')
        {
            arr[i + 1] = 1;
        }
        arr[i + 1] += arr[i];
    }
    ll ans = 0;
    for (int i = 1; i <= len; i++)//两层循环求答案,最后超时了
    {
        int j = i + 1;
        while (j <= len)
        {
            if (arr[j] == arr[i - 1])
            {
                ans += (i * (len - j + 1)) % P;
            }
            j++;
        }
    }
    cout << ans % P << endl;
}
 
int main()
{
 
    int tNum;
    cin >> tNum;
    for (int i = 0; i < tNum; i++)
    {
        solve();
    }
 
    return 0;
}

正确code:

#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#define ll long long
using namespace std;

const int N = 200010;
const long long P = 1e9 + 7;
int arr[N];

void solve()
{
    string s;
    cin >> s;

    int len = s.size();
    for (int i = 0; i < len; i++) //作前缀和,如果坐标对应的字符是'0'那么代表-1,如果是'1'那么代表+1
    {
        arr[i + 1] = arr[i];
        if (s[i] == '0')
        {
            arr[i + 1] += -1;
        }
        else if (s[i] == '1')
        {
            arr[i + 1] += 1;
        }
    }
    ll ans = 0;
    map<int, long long> m;
    m[0]++;      //这个m[0] ++是因为当出现第一个前缀和为0时m[0] = 0那样就会变成0 * (n - y + 1),正确的应该是
                 //1 * (n - y + 1),所以要加成一
    for (int i = 1; i <= len; i++)
    {
        ans += (len - i + 1) * m[arr[i]] % P; //y乘满足条件x坐标之和,因为题目数据范围大于10^9 + 7所以ans加上的值
		                              //可能大于10^9 + 7所以要提前模上
        m[arr[i]] += i + 1;    //更新满足条件x坐标之和
    }
    ans %= P;//后面也可能会大于10^9 + 7
    cout << ans << endl;
}

int main()
{

    int tNum;
    cin >> tNum;
    for (int i = 0; i < tNum; i++)
    {
        solve();
    }

    return 0;
}

标签:arr,前缀,962,int,Codeforces,Decode,测试用例,区间,include
From: https://www.cnblogs.com/chhh31/p/18331196

相关文章

  • Codeforces Round 961 (Div. 2) 复盘
    第一次打div2的总结div2难度明显比div3要难一些,其实也不是很难前面的签到题,但是给了我一种每道题都可以直接暴力但是就是会超时的感觉,不知道是不是提前就在告诉你要考虑greedythinking。T11995A-Diagonals这道题说实话就是存粹的模拟,除了最长的一个对角线同长度只有一列,其......
  • CF Div3 962补题 E-F
    CFDiv3962补题E-FE.Decode链接:Problem-E-Codeforces简要题意:给你一个长度为\(n\)的二进制字符串\(s\)。对于每一对整数\((l,r)\)\((1\leql\leqr\leqn)\)中,数出\((x,y)\)\((l\leqx\leqy\leqr)\)这样的整数对的个数。\((l\leqx\leqy\leq......
  • E. Decode
    https://codeforces.com/contest/1996/problem/E题意:给定一个01字符串s,统计区间[l,r]中,[x,y]([l,r]的子区间)中0和1出现次数相等的字符串。思路:维护一个cnt值,并计算以当前下标j结尾,所有满足条件的起始下标i中,对最后答案的总贡献是多少。一次遍历+map查询即可。总结:很容易想到......
  • codeforces 1209E2 Rotate Columns (hard version)
    codeforces1209E2RotateColumns(hardversion)题解题目传送门:codeforcces,luogu思路状压dp,贪心。贪心对于所有列,只有列中最大值在所有列的最大值中前\(n\)大才可能对答案有贡献。证明:若有非前\(n\)大的列对某行最大值产生了贡献,则用没有被取的前\(n\)大的列代......
  • Codeforces Round 961 (Div. 2)
    Preface菜的批爆,B2一直WA道心破碎了直接白兰去了,鉴定为纯纯的飞舞本来想着周末补题的然后又摆了一天,E1和E2都没时间补了,鉴定为纯纯的懒狗A.Diagonals签到,贪心枚举即可#include<cstdio>#include<iostream>#include<utility>#include<vector>#include<cstring>#in......
  • CodeForces 1883G1 Dances (Easy version)
    题目链接:CodeForces1883G1【Dances(Easyversion)】思路    为了使得数组a,b中的每个对应元素满足a[i]<b[i],所以将数组a,b按从小到大依次排列,优先删除数组a中较大的元素和数组b中较小的元素,由于删去的元素个数具有单调性,所以使用二分优化,计算最少要删去几个元素。......
  • CodeForces 1883F You Are So Beautiful
    题目链接:CodeForces1883F【YouAreSoBeautiful】思路    要找出一个子数组使得在数组中只能找出一个子序列和当前子数组相等,则只需要找出首元素的数字必须为当前元素值第一次出现,尾元素的数字必须为当前元素值最后一次出现,则只能找出唯一的子序列和当前子数组相等。......
  • codeforces 1209E1 Rotate Columns (easy version)
    codeforces1209E1RotateColumns(easyversion)题目传送门:codeforcces,luogu思路贪心,暴力搜索贪心对于所有列,只有列中最大值在所有列的最大值中前\(n\)大才可能对答案有贡献。证明:若有非前\(n\)大的列对某行最大值产生了贡献,则用没有被取的前\(n\)大的列代替该行......
  • Codeforces Round 962 (Div. 3) 题解 A-F
    A.LegsProblem-A-Codeforces1.1翻译农夫约翰的农场又迎来了美好的一天。农夫约翰来到农场后,数了数n条腿。众所周知,农场里只住着鸡和牛,一只鸡有2条腿,而一头牛有4条腿。假设约翰农场主数清了所有动物的腿,那么他的农场里最少有多少动物?1.2思路求最少有几只动物......
  • Codeforces Round 962 (Div. 3)
    题目链接:CodeforcesRound962(Div.3)总结:ABC秒过,D有点难评了,E优化很妙。A.Legstag:签到voidsolve(){cin>>n;inta=n/4,b=n%4;a+=b/2;cout<<a<<endl;}B.Scaletag:模拟voidsolve(){cin>>n>>k;......