2019.3.8 提高B组 T3 JZOJ 3056 数学

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88368932

D e s c i r p t i o n Descirption

一个数字被称为好数字当他满足下列条件:

  1. 它有2*n个数位,n是正整数(允许有前导0)

  2. 构成它的每个数字都在给定的数字集合S中。

    1. 它前n位之和与后n位之和相等或者它奇数位之和与偶数位之和相等

    例如对于n=2,S={1,2},合法的好数字有1111,1122,1212,1221,2112,2121,2211,2222这样8种。

已知 n n ,求合法的好数字的个数 m o d 999983 mod 999983

数据范围: n 1000 n\leq 1000


S o l u t i o n Solution

首先如果只用 S |S| 这个集合中的数时,前 n n 位之和与后 n n 位之和相等的数量是等于它奇数位之和与偶数位之和相等

自然而然想到了相乘

根据荣斥定理,我们只需要减去两个都满足的就可以我靠( w o r k   o u t work\ out )了

递推方程: f [ i ] [ j ] = f [ i 1 ] [ j a [ k ] ] f[i][j]=\sum f[i-1][j-a[k]]

时间复杂度: O ( 9 n 2 ) O(9n^2)


C o d e 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);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/88368932