一、题目
二、解法
虽然一眼看上去是数位 d p dp dp,但这长度 1 e 18 1e18 1e18明显不可做。
还是要找规律,首先有一个我这辈子都想不到的转化,原来是数是形如 11122233.... 11122233.... 11122233....,可以转化成 11111111.... 11111111.... 11111111...., 00011111.... 00011111.... 00011111...., 00000011.... 00000011.... 00000011....的叠加,设 c n t [ i ] cnt[i] cnt[i]为长度 n n n以内的,模 p p p余 i i i的数个数。
设
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k]为前
i
i
i类数中(按余数分的类),选了
k
k
k个数叠加,叠加后模
p
p
p余
j
j
j的方案数,显然这个转移类似背包:
d
p
[
i
+
1
]
[
j
]
[
k
]
=
d
p
[
i
]
[
j
−
l
×
i
]
[
k
−
l
]
×
C
c
n
t
i
+
l
−
1
l
dp[i+1][j][k]=dp[i][j-l\times i][k-l]\times C_{cnt_i+l-1}^l
dp[i+1][j][k]=dp[i][j−l×i][k−l]×Ccnti+l−1l初始化
d
p
[
0
]
[
s
]
[
0
]
=
1
dp[0][s][0]=1
dp[0][s][0]=1(必须选全
1
1
1,因为不能有前导零),重点解释一下最后那个组合数,因为每个数可以无限选,所以相当于解方程
x
1
+
x
2
.
.
.
=
l
x_1+x_2...=l
x1+x2...=l,由于每个是非负数解所以可以用隔板法算出方案数为
C
c
n
t
i
+
l
−
1
c
n
t
i
−
1
=
C
c
n
t
i
+
l
−
1
l
C_{cnt_i+l-1}^{cnt_i-1}=C_{cnt_i+l-1}^l
Ccnti+l−1cnti−1=Ccnti+l−1l
现在问题在于如何算 c n t cnt cnt,由于计算方式是单一的(乘10加1),利用抽屉原理可以知道最多 p + 1 p+1 p+1次就可以出现循环节,所以找到循环节之后就可以算了。
#include <cstdio>
#include <cstring>
#define int long long
const int M = 505;
const int MOD = 999911659;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,s,p,ans,sum,beg,len,inv[M];
int cnt[M],pos[M],c[M][M],dp[M][M][10];
signed main()
{
n=read();p=read();
if(n<=p)
{
for(int i=1;i<=n;i++) sum=(sum*10+1)%p,++cnt[sum];
s=sum;
}
else
{
for(int i=1;i<=p+1;i++)
{
sum=(sum*10+1)%p;
if(cnt[sum])
{
beg=pos[sum];len=i-pos[sum];
break;
}
++cnt[sum];pos[sum]=i;
}
for(int i=0;i<p;i++)
if(cnt[i] && pos[i]>=beg)
{
cnt[i]=(n-beg+1)/len;
if(pos[i]-beg+1<=(n-beg+1)%len) ++cnt[i];
if((pos[i]-beg+1)%len==(n-beg+1)%len) s=i;
}
}
inv[0]=inv[1]=1;
for(int i=2;i<=8;i++)
inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
for(int i=0;i<p;i++)
{
c[i][0]=1;
if(cnt[i])
for(int j=1;j<=8;j++)
{
c[i][j]=cnt[i]*c[i][j-1]%MOD*inv[j]%MOD;
cnt[i]=(cnt[i]+1)%MOD;
}
}
dp[0][s][0]=1;
for(int i=0;i<p;i++)
for(int j=0;j<p;j++)
for(int k=0;k<9;k++)
for(int l=0;l<=k;l++)
dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][(j-l*i%p+p)%p][k-l]*c[i][l]%MOD)%MOD;
for(int i=0;i<=8;i++)
ans=(ans+dp[p][0][i])%MOD;
printf("%lld\n",ans);
}