【问题描述】
一个数字被称为好数字当他满足下列条件:
1. 它有2*n个数位,n是正整数(允许有前导0)
2. 构成它的每个数字都在给定的数字集合S中。
3. 它前n位之和与后n位之和相等或者它奇数位之和与偶数位之和相等
例如对于n=2,S={1,2},合法的好数字有1111,1122,1212,1221,2112,2121,2211,2222这样8种。
已知n,求合法的好数字的个数mod 999983。
Input
第一行一个数n。
接下来一个长度不超过10的字符串,表示给定的数字集合。
Output
一行一个数字表示合法的好数字的个数mod 999983。
Sample Input
2 0987654321
Sample Output
1240
Data Constraint
Hint
对于20%的数据,n≤7。
对于100%的.据,n≤1000,|S|≤10。
题解
- 显然我们可以问题为:
-
前n位之和与后n位之和相等的方案数+奇数位之和与偶数位之和相等的方案数-前n位之和与后n位之和相等且奇数位之和与偶数位之和相等的方案数
- 根据容斥原理可以将最后一个转换为:
- 前n位奇数位之和=后n位偶数位之和 且 前n位偶数位之和=后n位奇数位之和
- 那么前两个都很容易求,跑一遍dp,f[i][j]表示i个数和为j的可能的方案数
- 那么i个数可以为n个奇数,也可以为n个偶数
- 那么前两个的和就是∑(i=1,i<=n*9)2*f[n][i]*f[n][i] (ans)
- 定义两个数l1=(n+1)/2,l2=n/2
- l1为前n个数的奇数个数和后n个数的偶数个数
- l2为前n个数的偶数个数和后n个数的奇数个数
- 知道这个后方案数自然很容易求
ans2=(ans2+f[l2][i]%mo*f[l2][i])%mo;ans1=(ans1+f[l1][i]%mo*f[l1][i])%mo;
- 答案为ans-ans1*ans2
- 注意要取膜
代码
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int mo=999983; 6 int n,len,a[15]; 7 long long ans1,ans2,sum,f[1005][1005*9]; 8 char s[15]; 9 int main() 10 { 11 scanf("%d",&n); 12 scanf("%s",s+1); 13 len=strlen(s+1); 14 for (int i=1;i<=len;i++) a[i]=s[i]-‘0‘; 15 f[0][0]=1; 16 for (int i=1;i<=n;i++) 17 for (int j=0;j<=i*9;j++) 18 for (int k=1;k<=len;k++) 19 if (j-a[k]>=0) 20 f[i][j]=(f[i][j]+f[i-1][j-a[k]])%mo; 21 for (int i=0;i<=n*9;i++) sum=(sum+2*f[n][i]%mo*f[n][i])%mo; 22 int l1=(n+1)/2,l2=n/2; 23 for (int i=0;i<=l1*9;i++) ans1=(ans1+f[l1][i]%mo*f[l1][i])%mo; 24 for (int i=0;i<=l2*9;i++) ans2=(ans2+f[l2][i]%mo*f[l2][i])%mo; 25 printf("%lld",(sum-ans1*ans2%mo+mo)%mo); 26 }
原文地址:https://www.cnblogs.com/Comfortable/p/8562344.html
时间: 2024-10-09 17:29:52