[Jzoj] 3056.数字

题目大意

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

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

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

题目解析

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

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

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

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

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

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

代码

#include
#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=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<

你可能感兴趣的:([Jzoj] 3056.数字)