题意:给你一个数字串,问有多少个连续子串被质数Q整除
一道有趣的数论题
对于长度为n的字符串
num[i][j]:下标从i~j的子串
(1)
Q=2或Q=5
,容易处理
(2)
Q≠2且Q≠5
num[i][n]=num[j][n]+num[i][j]×10k
移项得
num[i][j]×10k≡num[i][n]−num[j][n]
故
Q∣num[i][j]<==>Q∣num[i][n]−num[j][n]
然后就可以各种姿势随便搞搞就OK
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
int N, S, W, Q;
int a[MAXN], num[MAXN];
void init()
{
for(int i = 0; i < N; i++)
{
a[i] = (S / 7) % 10;
if(S % 2 == 0) S /= 2;
else S = (S / 2) ^ W;
}
num[N - 1] = a[N - 1] % Q;
int t = 10;
for(int i = N - 2; i >= 0; i--)
{
num[i] = ((ll)a[i] * t + num[i + 1]) % Q;
t = (t * 10) % Q;
}
}
int solve1()
{
int res = 0, cnt = 0;
for(int i = N - 1; i >= 0; i--)
{
if(a[i] != 0)
{
res += cnt;
if(a[i] % Q == 0) cnt++, res++;
}
else
cnt++;
}
return res;
}
int solve2()
{
int res = 0;
map<int,int> M;
for(int i = N - 1; i >= 0; i--)
{
if(a[i] != 0)
{
res += M[num[i]];
if(num[i] == 0) res++;
}
M[num[i]]++;
}
return res;
}
int main()
{
while(scanf("%d%d%d%d", &N, &S, &W, &Q) && N != 0)
{
init();
if(Q == 2 || Q == 5) printf("%d\n", solve1());
else printf("%d\n", solve2());
}
}