hdu 5291 Candy Distribution 2015 Multi-University Training Contest 1

来源:互联网 发布:javascript 教程 pdf 编辑:程序博客网 时间:2024/05/23 01:20


Candy Distribution

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 234    Accepted Submission(s): 80


Problem Description
WY has n kind of candy, number 1-N, The i-th kind of candy has ai. WY would like to give some of the candy to his teammate Ecry and lasten. To be fair, he hopes that Ecry’s candies are as many as lasten's in the end. How many kinds of methods are there?
 

Input
The first line contains an integer T<=11 which is the number of test cases. 
Then T cases follow. Each case contains two lines. The first line contains one integer n(1<=n<=200). The second line contains n integers ai(1<=ai<=200)
 

Output
For each test case, output a single integer (the number of ways that WY can distribute candies to his teammates, modulo 109+7 ) in a single line.
 

Sample Input
21221 2
 

Sample Output
24
Hint
Sample: a total of 4, (1) Ecry and lasten are not assigned to the candy; (2) Ecry and lasten each to a second kind of candy; (3) Ecry points to one of the first kind of candy, lasten points to a second type of candy; (4) Ecry points to a second type of candy, lasten points to one of the first kind of candy.
 

Author
FZUACM
 

Source
2015 Multi-University Training Contest 1






动态规划,包含处理等差数列的技巧,见代码。


对于一个非负整数k,要得到比他大的偶数 2*(k/2+1);

                                 要得到比他大的奇数  2*  (k+1)/2+1;




#include <iostream>#include<cstdio>#include<cstring>const int maxn=200+10;const int maxa=200+10;typedef long long ll;const ll mod=1000000000+7;int data[maxn];ll dp[2][maxn*maxa*2];//解决爆内存的方法。这个我想到了。ll a[maxn*maxa*2];//本来超过20000就不用讨论,所以一开始我开的是40000+,//但是还得将数组开大一点,因为,下面的计算方法,必须到达可能存在的值using namespace std;int base=40005;inline int f(int x)  //不能直接处理负值{    return x+base;}void even(int st ,int num,int add){    a[f(st)]+=add;    a[f(st+2*num)]-=2*add;    a[f(st+4*num)]+=add;}void odd(int st,int num,int add){    a[f(st)    ]+=add;    a[f(st+2*num)]-=add;    a[f(st+2*num+2)]-=add;    a[f(st+4*num+2)]+=add;}int main(){//   freopen("in.txt","r",stdin);//  freopen("out.txt","w",stdout);    int T;scanf("%d",&T);    while(T--)    {        int n;scanf("%d",&n);        for(int i=1;i<=n;i++)  scanf("%d",&data[i]);        int now=0,pre=1; memset(dp,0,sizeof dp);dp[now][f(0)]=1;        int limit=0;        for(int i=1;i<=n;i++)        {            now^=1,pre^=1;            limit= limit+data[i];            for(int j=-limit-2;j<=limit+2;j++  )                dp[now][f(j)]=0,a[f(j)]=0;            for(int j=-limit-2;j<=limit+2;j++)            {                if(!dp[pre][f(j)])  continue;                 int val=data[i];                 int num=val/2+1  ;even(j-2*num   ,num,dp[pre][f(j)]  );                     num=(val+1)/2;odd(j-2*num-1, num,dp[pre][f(j)] );            }             ll s=0,v=0;            //解决超时的方法,这个想不到,当初只会暴力的二重循环o(n^2);            /*            这个先对上一组dp的值,顺次遍历,考虑对现在所求dp组的贡献            然后对现在的dp组顺次遍历,直接求得答案,复杂度应该是O(n+n);            大大节约了时间            */             for(int j=-limit-2; j<=limit+2;j+=2)            {                a[f(j)]=(a[f(j)]%mod+mod)%mod;  //忘记了这个取模的方法,  ( %mod+mod)%mod;                s=(s+v)%mod;                dp[now][f(j)]=s;                v=(v+a[f(j)])%mod;            }            s=v=0;            for(int j=-limit-1;j<=limit+2;j+=2)            {                a[f(j)]=(a[f(j)]%mod+mod)%mod;                s=(s+v)%mod;                dp[now][f(j)]=s;                v=(v+a[f(j)])%mod;            }        }        printf("%I64d\n",dp[now][f(0)]);  //靠,直接写成了dp[n][f(0)];    }    return 0;}
0 0
原创粉丝点击