可能中奖?一定中奖
题目描述
一张彩票上印有2*K个数字,每个数字都是0至9中的某一个,只要满足如下两个条件的任意一个,那么彩票就是“可能中奖彩票”:
1、彩票前K个数字的总和等于最后K个数字的总和。
2、下标是奇数的所有数字的总和 必须等于 下标是偶数的所有数字的总和。
给出数组:lucky[1…n],其中 1 <=n <= 10, 0<=lucky[i]<=9,每一个lucky[i]都是“幸运数字”,lucky[i]互不相同。
如果一张彩票是“可能中奖彩票”,而且该彩票的每一个数字都是“幸运数字”,那么该彩票就是“一定中奖彩票”。
问题是:总共有多少张不同的“一定中奖彩票”? 答案模999983。 请记住,“一定中奖彩票”可能包含前导零。
输入格式
多组测试数据。
第一行,一个整数G,表示有G组测试数据。 1 <= G <= 6
每组测试数据格式:
第一行,两个整数,K和n 。1 <= K <= 50, 1<=n<=10。
第二行,n个整数,第i个整数是lucky[i]。 0<=lucky[i]<=9, lucky[i]互不相同。
输出格式
共G行,每行一个整数。
输入样例
6
1 10
0 1 2 3 4 5 6 7 8 9
2 2
2 1
2 10
0 1 2 3 4 5 6 7 8 9
10 3
7 3 1
50 10
0 1 2 3 4 5 6 7 8 9
46 8
2 8 7 5 9 6 0 4
输出样例
10
8
1240
207444
367584
537052
解题思路
题目大意:给出一个lucky数组,求有多少张“一定中奖彩票”。
从题目中我们知道,目标数列符合以下条件:
- 有 2 × K 2\times K 2×K个数字
- 这 2 × K 2\times K 2×K个数字必须是lucky数组中的任意一个
- 彩票前K个数字的总和等于最后K个数字的总和
或者
下标是奇数的所有数字的总和 必须等于 下标是偶数的所有数字的总和
我们根据容斥原理可以得知
设满足第3个条件的第1个条件以及其它必备条件为种类A
设满足第3个条件的第2个条件以及其它必备条件为种类B
设满足第3个条件当中的所有条件以及其它必备条件为种类C
A n s = A + B − C Ans=A+B-C Ans=A+B−C
A A A怎么求呢?动态规划!
我们先将这 2 × K 2\times K 2×K个数字分成2部分,前 K K K个为一部分,后 K K K个为一部分
求出前一部分总和为 i i i的方案数 F i F_i Fi,那么根据乘法原理两个部分总和为 i i i的的方案数就是 F i × F i 即 F i 2 F_i\times F_i即F_i^2 Fi×Fi即Fi2
所有总和情况的方案数就是 ∑ i = 1 t o t F i × F i \sum_{i=1}^{tot}F_i\times F_i i=1∑totFi×Fi
设 f [ i ] [ j ] f[i][j] f[i][j]表示当前选了lucky数组里的 i i i个数字,总和为 j j j的方案数
f [ i ] [ j ] = ∑ k = 1 n f [ i − 1 ] [ j − l u c k y [ k ] ] f[i][j]=\sum_{k=1}^{n}f[i-1][j-lucky[k]] f[i][j]=k=1∑nf[i−1][j−lucky[k]]
将 f [ i ] [ j ] f[i][j] f[i][j]代入总求和式子
∑ i = 1 t o t f [ K ] [ i ] × f [ K ] [ i ] \sum_{i=1}^{tot}f[K][i]\times f[K][i] i=1∑totf[K][i]×f[K][i]
求 B B B的方法与求 A A A的一样,为什么呢?
好了,到这一步我们要求 C C C情况的方案数
这时我们利用刚刚求出的 f f f,枚举 s u m 1 , s u m 2 sum1,sum2 sum1,sum2:
前 K K K个奇数位置:1,3对应了 f [ K − K / 2 ] [ s u m 1 ] f[K-K/2][sum1] f[K−K/2][sum1]
前 K K K个偶数位置:2,4对应 f [ K / 2 ] [ s u m 2 ] f[K/2][sum2] f[K/2][sum2]
后 K K K个奇数位置:7,9对应 f [ K / 2 ] [ s u m 2 ] f[K/2][sum2] f[K/2][sum2]
后 K K K个偶数位置:6,8对应了 f [ K − K / 2 ] [ s u m 1 ] f[K-K/2][sum1] f[K−K/2][sum1]
结果就是 f [ K − K / 2 ] [ s u m 1 ] × f [ K / 2 ] [ s u m 2 ] × f [ K − K / 2 ] [ s u m 1 ] × f [ K / 2 ] [ s u m 2 ] f[K-K/2][sum1]\times f[K/2][sum2]\times f[K-K/2][sum1]\times f[K/2][sum2] f[K−K/2][sum1]×f[K/2][sum2]×f[K−K/2][sum1]×f[K/2][sum2]
本题终于完成。
代码
/*
条件:
1、彩票前K个数字的总和等于最后K个数字的总和。
2、下标是奇数的所有数字的总和 必须等于 下标是偶数的所有数字的总和。
3、而且该彩票的每一个数字都是“幸运数字”
同时满足1,3的情况为A
同时满足2,3的情况为B
同时满足1,2,3的情况为C
根据容斥原理,可知
答案=A+B-C
A,B的求法:往K个空位里填n个幸运数字,用动态规划求解
C的求法:在2*K个数字里,将这些数字根据条件1,2分成几组
例如当K=5时,枚举sum1,sum2
前K个奇数位置:1,3,5对应了f[K-K/2][sum1]
前K个偶数位置:2,4对应f[K/2][sum2]
后K个奇数位置:7,9对应f[K/2][sum2]
后K个偶数位置:6,8,10对应了f[K-K/2][sum1]
将这4种情况相乘,得出c
求和sum1*sum2种相同c情况得到C
*/
#include<bits/stdc++.h>
using namespace std;
int G,K,n;
long long f[55][500],lucky[20];
long long ans;
int main()
{
freopen("2788.in","r",stdin);
freopen("2788.out","w",stdout);
cin>>G;
for(int gr=1;gr<=G;gr++)
{
cin>>K>>n;
ans=0;
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
cin>>lucky[i];
f[1][lucky[i]]=1;
if(lucky[i]==0)//当幸运数字里有0时,选K个幸运数字,和为0的情况只有1种
{
for(int j=0;j<=K;j++)
f[j][0]=1;
}
}
for(int i=2;i<=K;i++)
{
for(int j=1;j<=450;j++)
for(int l=1;l<=n;l++)
{
if(j>=lucky[l])
{
f[i][j]+=f[i-1][j-lucky[l]]%999983;//dp求方案数
f[i][j]%=999983;
}
}
}
for(int j=0;j<=450;j++)
{
ans+=(f[K][j]*f[K][j])%999983;//求出A
ans%=999983;
ans+=(f[K][j]*f[K][j])%999983;//求出B
ans%=999983;
}
for(int i=0;i<=450;i++)//枚举sum1
{
for(int j=0;j<=450;j++)//枚举sum2
{
long long a=f[K/2][i]*f[K-K/2][j]%999983;
ans-=(a*a)%999983;
if(ans<0)//当答案出现负数时,加上模数确保答案正确
ans+=999983;
ans%=999983;
}
}
cout<<ans<<endl;
}
return 0;
}