[Jzoj] 3056.数字

题目大意

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

  1. 它有 2 n 2*n 个数位, n n 是正整数(允许有前导 0 0 )
  2. 构成它的每个数字都在给定的数字集合 S S 中。
  3. 它前 n n 位之和与后 n n 位之和相等或者它奇数位之和与偶数位之和相等

已知n,求合法的好数字的个数mod 999983。

题目解析

a n s = ans= 前n位之和与后n位之和相等的方案数+奇数位之和与偶数位之和相等的方案数-前n位之和与后n位之和相等且奇数位之和与偶数位之和相等的方案数

前2个需要+的方案数都很好求,直接递推

重点是最后一个要满足2个条件的方案数怎么求,其实也很简单:

因为前n位之和=后n位之和,奇数位之和=偶数位之和

所以前n位中奇数位之和=后n位中偶数位之和 且 前n位中偶数位之和=后n位中奇数位之和

现在只要求上面这个问题的方案数,由于两个等式中的元素无交集,也是十分好算的。

代码

#include<bits/stdc++.h>
#define M 999983
#define L long long
using namespace std;
L n,len,ans,l1,l2,ans1,ans2;
L a[11],f[1005][10005];
string s;
int main()
{
	cin>>n>>s;
	len=s.size();
	for(int i=0;i<len;i++)
	 a[i+1]=s[i]-48;
	f[0][0]=1;
	for(int i=1;i<=n;i++)
	 for(int j=0;j<=i*9;j++)
	  for(int k=1;k<=len;k++)
	   if(j-a[k]>=0)
	    (f[i][j]+=f[i-1][j-a[k]])%=M;
	for(int i=0;i<=n*9;i++)
	 (ans+=2*f[n][i]*f[n][i])%=M;
	l1=(n+1)/2;l2=n/2;
	for(int i=0;i<=l1*9;i++)
	 (ans1+=f[l1][i]*f[l1][i])%=M;
	for(int i=0;i<=l2*9;i++)
	 (ans2+=f[l2][i]*f[l2][i])%=M;
	ans=(ans-ans1*ans2%M+M)%M;
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/weixin_43909855/article/details/88366547