D e s c i r p t i o n Descirption Descirption
一个数字被称为好数字当他满足下列条件:
-
它有2*n个数位,n是正整数(允许有前导0)
-
构成它的每个数字都在给定的数字集合S中。
- 它前n位之和与后n位之和相等或者它奇数位之和与偶数位之和相等
例如对于n=2,S={1,2},合法的好数字有1111,1122,1212,1221,2112,2121,2211,2222这样8种。
已知 n n n,求合法的好数字的个数 m o d 999983 mod 999983 mod999983。
数据范围: n ≤ 1000 n\leq 1000 n≤1000
S o l u t i o n Solution Solution
首先如果只用 ∣ S ∣ |S| ∣S∣这个集合中的数时,前 n n n位之和与后 n n n位之和相等的数量是等于它奇数位之和与偶数位之和相等
自然而然想到了相乘
根据荣斥定理,我们只需要减去两个都满足的就可以我靠( w o r k o u t work\ out work out)了
递推方程: f [ i ] [ j ] = ∑ f [ i − 1 ] [ j − a [ k ] ] f[i][j]=\sum f[i-1][j-a[k]] f[i][j]=∑f[i−1][j−a[k]]
时间复杂度: O ( 9 n 2 ) O(9n^2) O(9n2)
C o d e Code Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define WYC 999983
using namespace std;int n,a[10],m;
char s[10];
long long f[1010][9010];
long long S(int x)
{
long long ans=0;
for(register int i=0;i<=x*9;i++) if(f[x][i]) (ans+=f[x][i]*f[x][i]%WYC)%WYC;
return ans;
}
signed main()
{
scanf("%d\n",&n);
scanf("%s",s);
m=strlen(s);
for(register int i=0;i<m;i++) a[i]=s[i]-48;
f[0][0]=1;
for(register int i=0;i<=n;i++)
for(register int j=0;j<=9*n;j++)
if(f[i][j])
for(register int k=0;k<m;k++)
(f[i+1][j+a[k]]+=f[i][j])%=WYC;
printf("%lld",(2*S(n)%WYC-S(n/2)*S(n-n/2)%WYC+WYC)%WYC);
}