Description
对于kkk进制数xxx,定义d(x)d(x)d(x)为xxx的各数位的和的kkk进制表示,如果结果超过一位,则继续重复执行各数位求和操作,直至结果为111位。
比如说,在777进制下,d(35047)=d((3+5+0+4)7)=d(157)=d((1+5)7)=d(67)=6d(3504_7)=d((3+5+0+4)_7)=d(15_7)=d((1+5)_7)=d(6_7)=6d(35047)=d((3+5+0+4)7)=d(157)=d((1+5)7)=d(67)=6
定义xxx为幸运的,当且仅当d(x)=bd(x) = bd(x)=b;
现在给定kkk进制下的nnn个数位a1a2...ana_1 a_2 ...a_na1a2...an,问其中有多少子串组成的数字是幸运的。
Input
第一行三个整数k,b,nk,b,nk,b,n
第二行nnn个整数aia_iai
(2≤k≤109,0≤b<k,1≤n≤105,0≤ai<k)(2\le k\le 10^9,0\le b<k,1\le n\le 10^5,0\le a_i<k)(2≤k≤109,0≤b<k,1≤n≤105,0≤ai<k)
Output
输出一个整数表示幸运的子串数。
Sample Input
10 5 6
3 2 0 5 6 1
Sample Output
5
Solution
显然d(x)=(x−1)%(k−1)+1d(x)=(x-1)\%(k-1)+1d(x)=(x−1)%(k−1)+1,d(x)=0d(x)=0d(x)=0当且仅当xxx每位都为000,首先统计连续为000的段的个数resresres,如果b=0b=0b=0则答案即为resresres,如果b=k−1b=k-1b=k−1,为方便统计,直接令d(x)=x%(k−1)d(x)=x\%(k-1)d(x)=x%(k−1),如此求出的满足d(x)=0d(x)=0d(x)=0的子串本质上是d(x)=0,k−1d(x)=0,k-1d(x)=0,k−1的子串数量和,该值减去resresres即为答案
现在考虑求满足d(x)=bd(x)=bd(x)=b的子串个数,令si=(a1+...+ai)%(k−1)s_i=(a_1+...+a_{i})\%(k-1)si=(a1+...+ai)%(k−1),那么以iii为右端点的合法区间[j,i][j,i][j,i]需要满足si−sj−1≡b(mod k−1)s_i-s_{j-1}\equiv b(mod\ k-1)si−sj−1≡b(mod k−1),用mapmapmap统计每种前缀和出现次数即可
Code
#include<cstdio>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=100005;
map<int,int>M;
int k,b,n,a[maxn];
int main()
{
scanf("%d%d%d",&k,&b,&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
ll ans=0;
for(int i=1,pre=1;i<=n;i++)
{
if(a[i])pre=i+1;
else ans+=i-pre+1;
}
if(b==0)
{
printf("%lld\n",ans);
return 0;
}
if(b==k-1)ans=-ans,b=0;
else ans=0;
M[0]=1;
for(int i=1,res=0;i<=n;i++)
{
res=(res+a[i])%(k-1);
ans+=M[(res-b+k-1)%(k-1)];
M[res]++;
}
printf("%lld\n",ans);
return 0;
}