题目大意
给定 P,K,N ,求出有多少对 x,y ,满足 x≤y≤N , CxymodpK=0
数据范围
N≤101000
1≤P,K≤109
P
为质数
题解
首先,
并且可以发现的是,设 a 为最大的,满足
a=⌊np⌋+⌊np2⌋+⋯+⌊npw⌋ ,其中满足 pw≤n<pw+1 。
那么事实上最大的
a
满足
那么假如给定了 x,y ,我们只需要判断是否 k≤a 即可。
我们再仔细观察,假如我们将
x,y
都转化为
p
进制,那么
那么这题就可以做了。
我们设
Fi,j,eq,rem
表示当前由大到小,要确定第
i
位,
一种简单的转移就是枚举下一位是否要进位,
x,y
这一位取的数字,然后判断是否合法即可。但这样太慢了,是
O(P2)
的。
但再想一下,没有必要枚举
x,y
取得数字,可以直接用公式计算出来,具体的自己写几个数字就可以发现了,类似于等差数列求和,注意要特殊考虑进位的情况。
并且我们一开始需要将
N
转化为
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 3505,Mo = int(1e9) + 7;
char B[MAXN];
int F[MAXN][MAXN][2][2];
int A[MAXN],p,a,L;
int Divide(char *a,int p)
{
int rem = 0;
for(int i = L;i;i --)
{
LL bk = rem * 10LL + a[i];
rem = bk % p;
a[i] = bk / p;
}
for(;L && !a[L];L --);
return rem;
}
int Mul(int a,int b)
{
return a * 1ll * b % Mo;
}
int Dec(int a,int b)
{
return (a - b + Mo) % Mo;
}
void Inc(int &a,int b)
{
a = (a + b) % Mo;
}
int Get_P(int c,int r,int nr)
{
if (r) return Dec(p,Get_P(c,0,nr));
return c - nr + 1;
}
int Get_S(int c,int r,int nr)
{
if (r) return Dec(Mul(c + 1,p),Get_S(c,0,nr));
if (c & 1) return Dec(Mul(c + 2,(c + 1) >> 1),nr * (c + 1));
return Dec(Mul(c + 1,(c + 2) >> 1),nr * (c + 1));
}
int main()
{
//freopen("data.in","r",stdin),freopen("data.out","w",stdout);
scanf("%d%d", &p, &a);
scanf("%s", B + 1);
L = strlen(B + 1);
for(int i = 1;i <= L;i ++) B[i] = B[i] - '0';
reverse(B + 1,B + L + 1);
int n = 0;
for(;L;)
A[++ n] = Divide(B,p);
reverse(A + 1,A + n + 1);
if (a > n) {printf("0\n");return 0;}
F[1][0][1][0] = 1;
for(int i = 1;i <= n;i ++)
for(int j = 0;j <= a;j ++)
for(int eq = 0;eq < 2;eq ++)
for(int rem = 0;rem < 2;rem ++)
if (F[i][j][eq][rem])
{
int cur = F[i][j][eq][rem];
for(int nr = 0;nr < 2;nr ++)
{
int nj = min(j + nr,a);
if (!eq)
Inc(F[i + 1][nj][eq][nr],Mul(cur,Get_S(p - 1,rem,nr))); else
{
Inc(F[i + 1][nj][eq][nr],Mul(cur,Get_P(A[i],rem,nr)));
if (A[i]) Inc(F[i + 1][nj][0][nr],Mul(cur,Get_S(A[i] - 1,rem,nr)));
}
}
}
int ans = 0;
for(int eq = 0;eq < 2;eq ++)
Inc(ans,F[n + 1][a][eq][0]);
printf("%d\n", ans);
return 0;
}