题目链接:点击查看
题目大意:给出一个由0或1组成的字符串s,用来构造出字符串 t = s + s + s....+ s,字符串 t 由无限个 s 拼接而成。现在规定cnt_0 [ i ]和cnt_1 [ i ]分别为到第 i 位为止所出现的0和1的个数,给出一个 x ,问字符串 t 中有多少个前缀满足cnt_0 [ i ] - cnt_1 [ i ] == x,若有无限个答案,输出-1
题目分析:简单到不能在简单的数学题了,但是比赛的时候脑子瓦特了,一直处理不了细节,加上读题的时候就把心态读崩了,正所谓是半小时读题,一秒钟出正解,一小时debug,然后交上去1WA,心态直接炸裂,完成掉分
读完题后,第一反应应该是有一个公式的,因为字符串 t 是由字符串 s 无限循环而得到的,每次循环后都必定会有数字0和数字1差值积累的贡献,比如字符串101,每循环一次所积累的差值为 -1 ,循环100次积累的差值就是 -100 ,所以我们可以分为两类,一类是可以积累贡献的,另一类是不能积累贡献的(也就是0的个数和1的个数相同时),当然输出-1的情况显然在不能积累贡献的情况中,我们假设找到 x 时是在第 k 次循环,那么有公式:
k * ( cnt_0 [ n ] - cnt_1 [ n ] ) + ( cnt_0 [ i ] - cnt_1 [ i ] ) == x
移项处理得到:
k * ( cnt_0 [ n ] - cnt_1 [ n ] ) == x - ( cnt_0 [ i ] - cnt_1 [ i ] )
满足上述条件的 i 就是我们所要找的答案了,需要满足两个条件:
- 因为积累贡献的 k 是从 0 开始的,所以第一个条件为(x - ( cnt_0 [ i ] - cnt_1 [ i ] )) / ( cnt_0 [ n ] - cnt_1 [ n ] ) >=0
- 其次就是 (x - ( cnt_0 [ i ] - cnt_1 [ i ] )) % ( cnt_0 [ n ] - cnt_1 [ n ] ) == 0
当然众所周知 0 不能作为除数出现,所以要分类讨论一下( cnt_0 [ n ] - cnt_1 [ n ] ) == 0时的情况,也就是不能积累贡献的情况,还有空串的情况也需要特判
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
int cnt[N];
char s[N];
int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);
int w;
cin>>w;
while(w--)
{
int n,x;
scanf("%d%d%s",&n,&x,s+1);
for(int i=1;i<=n;i++)
{
cnt[i]=cnt[i-1];
if(s[i]=='0')
cnt[i]++;
else
cnt[i]--;
}
int ans=0;
if(x==0)//特判空串
ans++;
for(int i=1;i<=n;i++)
{
if(cnt[n]==0)//每次循环贡献为0
{
if(cnt[i]==x)
ans++;
}
else//每次循环都有贡献
{
if((x-cnt[i])%cnt[n]==0&&(x-cnt[i])/cnt[n]>=0)
ans++;
}
}
if(cnt[n]==0&&ans)//特判无限
ans=-1;
printf("%d\n",ans);
}
return 0;
}