您的位置:首页 > 大数据 > 人工智能

hdu 5291 Candy Distribution 2015 Multi-University Training Contest 1

2015-07-24 14:56 387 查看



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

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

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
[f(0)];

    }

    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: