hdu 5291 Candy Distribution 2015 Multi-University Training Contest 1



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 10 9+7 ) in a single line.
 

Sample Input
  
  
2 1 2 2 1 2
 

Sample Output
  
  
2 4
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






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


对于一个非负整数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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值