参考大佬的思路发现能更清晰解决蓝桥杯的问题:女少口阿
链接:C. Good Subarrays
题意:给出一个0~9的字符串,求出任意字串和与字串长度相等的字串数目。
思路:
- 若字符为1自身就满足一个字串
- 若为2—9,任意值其后就要跟1—8个0才能满足这个字串和和长度相等
- 所以这里把0看作-1,把1看作0,把2—9看作1—8
- 记录每个前缀和出现的次数
思想:若1–i前缀和为3, 1—
i
+
k
1
i+k_1
i+k1的前缀和也为3,1—
i
+
k
2
i+k_2
i+k2的前缀和也是3……
那么i+1—
i
+
k
1
i+k_1
i+k1,i+1—
i
+
k
2
i+k_2
i+k2的前缀和就为0
/*
事实上并没有记录前缀和数组
我们用map数组记录了每个前缀和出现的次数
*/
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+5;
int T, n;
char a[N];
map<int,int> mp;
int main(){
int T;
scanf("%d",&T);
while(T--){
mp.clear();
scanf("%d",&n);
scanf("%s",a+1);
int x=0;
for(int i=1;i<=n;i++){
x+=a[i]-'0'-1;
mp[x]++;
}
long long ans=mp[0]; //前缀和为0的本身即为答案
x=0;
for(int i=1;i<=n;i++){
x+=a[i]-'0'-1;
mp[x]--;
ans+=mp[x]; //加上去掉1~i后符合要求了的子串数目
}
printf("%lld\n",ans);
}
return 0;
}
K倍区间问题:https://www.acwing.com/problem/content/1232/
以同样的思路解决
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
const int N=1e5+5;
typedef long long LL;
int a[N];
map<int,int> mp;
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
LL x=0;
for(int i=1;i<=n;i++){
x+=a[i];
mp[x%k]++;
}
int ans=mp[0];
x=0;
for(int i=1;i<=n;i++){
x+=a[i];
mp[x%k]--;
ans+=mp[x%k];
}
printf("%lld\n",ans);
return 0;
}