DP - hdu5291 Candy Distribution
来源:互联网 发布:编程电脑配置要求2017 编辑:程序博客网 时间:2024/05/17 03:05
题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5291
题意:
给若干种糖果,每种糖果数量不一定相等,现需要将所有糖果分成两份,要求两份糖果数量相等,问有多少种分法?【可以不必将所有糖果分完,如全部不分,每份糖果数量为0,也是一种分法】
思路:
求有多少分法的题目一般都是dp……
dp[i][j]:只使用前i种糖果的情况下,第一份比第二份多j个糖果的分法总数,j的值可能为负数,处理时应加上一个常数使j恒为正数
朴素的dp转移方程:
dp[i][j+x] += dp[i-1][j]
其中x的取值是-arr[i] ~ arr[i],arr[i]为第i种糖果的数量,表示只用第i种糖果,第一份可以比第二份多x个
这样解时间复杂度是O(n^4),n=200,分别为n种糖果,n^2的糖果数量(j的取值应为所有糖果的总数*2),转移时每个状态可以转移到2*n个状态,所以共O(n^4)
显然前三个n是没法优化的,考虑能否把状态转移的时间复杂度降为O(1)
思考每个状态dp[i-1][j]对dp[i][...]的贡献,dp[i][j]=dp[i-1][j-x]*((arr[i]-x)/2+1) + dp[i-1][j-(x-1)]*((arr[i]-(x-1)/2+1)) + ... + dp[i-1][j]*(arr[i]/2+1) + ... + dp[i-1][j+x]*((arr[i]-x)/2+1)
可以看到dp[i][j]是dp[i-1][j-x] ~ dp[i-1][j+x]乘上对应权值之和,而权值序列是一个按奇偶序列分布的等差数列
若arr[i] = 3,权值序列为1 1 2 2 2 1 1
若arr[i] = 2,权值序列为1 1 2 1 1
观察找到规律,通过sum数组预处理,即可在O(1)的时间复杂度下完成状态转移
代码:
<span style="font-family:Courier New;">#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<math.h>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<map>#include<set>#include<functional>#pragma comment(linker, "/STACK:102400000,102400000")//C++using namespace std;const double PI = 3.141592653589793238462643383279502884197169399;const int MAXINT = 0x7fffffff;const int MAXSIZE = 200+30;const int MOD = 1e9 + 7;int main(){ int total; int n; long long dp[2*MAXSIZE*MAXSIZE]; int arr[MAXSIZE]; long long sum[2*MAXSIZE*MAXSIZE]; const int banl = MAXSIZE*MAXSIZE; int candy=0; cin>>total; while (total--){ scanf("%d",&n); memset(arr,0,sizeof(arr)); memset(dp,0,sizeof(dp)); candy = 0; for (int i=0;i<n;++i){ scanf("%d",arr+i); candy+=arr[i]; } dp[banl] = 1; for (int i=0;i<n;++i){ memset(sum,0,sizeof(sum)); if (arr[i]%2){ for (int j=-candy + banl - arr[i]; j <= -candy + banl;j+=2) sum[-candy + banl - 1] = sum[-candy + banl -1] + dp[j]; for (int j=-candy + banl - arr[i] + 1; j<= -candy + banl + 1; j+=2) sum[-candy + banl] = sum[-candy + banl] + dp[j]; for (int j=-candy + banl + 1;j<=candy + banl + arr[i]; ++j){ sum[j] = sum[j-2] - dp[j-2-arr[i]+1] + dp[j]; } } else { for (int j=-candy + banl - arr[i]; j <= -candy + banl;j+=2) sum[-candy + banl] = sum[-candy + banl] + dp[j]; for (int j=-candy + banl - arr[i] + 1; j<= -candy + banl + 1; j+=2) sum[-candy + banl + 1] = sum[-candy + banl + 1] + dp[j]; for (int j=-candy + banl + 2;j<=candy + banl + arr[i]; ++j){ sum[j] = sum[j-2] - dp[j-arr[i]-2] + dp[j]; } } dp[-candy + banl] = (dp[-candy + banl] * (arr[i]/2+1)) % MOD; for (int j=1;j<=arr[i];++j) dp[-candy + banl] = (dp[-candy + banl] + dp[-candy + banl + j] * ((arr[i] - j)/2+1)) % MOD; if (arr[i]%2){ for (int j=-candy + banl + 1;j<=candy + banl; ++j) dp[j] = (dp[j-1] - sum[j-2] + sum[j+arr[i]]) % MOD; } else{ for (int j=-candy + banl + 1;j<=candy+ banl; ++j) dp[j] = (dp[j-1] - sum[j-1] + sum[j+arr[i]]) % MOD; } //for (int k=-candy;k<=candy;++k){ // cout<<"dp["<<i<<"]["<<k<<"]: "<<dp[banl+k]<<endl; //} } //for (int k=-candy;k<=candy;++k){ // cout<<"dp["<<n<<"]["<<k<<"]: "<<dp[banl+k]<<endl; //} int res = dp[banl]; res %= MOD; res = (res+MOD)%MOD; cout<<res<<endl; } return 0;}</span>
- DP - hdu5291 Candy Distribution
- 【DP】HDOJ 5291 Candy Distribution
- hdu 5291 Candy Distribution(dp)
- 【HDU】5291 Candy Distribution 【DP+打标记】
- HDU 5291(Candy Distribution-差值dp)
- Candy Distribution
- 【多校第一场】【dp】 HDU 5291 Candy Distribution
- PKU 3327 Candy Distribution
- 3372 Candy Distribution
- POJ 3372 Candy Distribution
- poj 3372 Candy Distribution
- poj3372-Candy Distribution
- Poj 3372 Candy Distribution
- Poj 3372 Candy Distribution
- poj3372-Candy Distribution
- POJ 3372 Candy Distribution
- POJ - 3372 Candy Distribution
- hdu 5291 Candy Distribution 2015 Multi-University Training Contest 1 树形dp,
- Java反射机制之集合泛型的本质
- 支持向量机
- Java字符串切割
- HDU 1257.最少拦截系统【8月9】
- poj2492 A Bug's Life 并查集
- DP - hdu5291 Candy Distribution
- python爬虫抓取LeetCode题目
- 101. Symmetric Tree
- 装wampserver时显示计算机丢失MSVCR110.dll
- hdu 1142(最短路dijkstra)
- 【Qt OpenGL教程】21:线、反走样、正投影和简单的声音
- C++:复制构造函数___浅拷贝
- UVA - 1442 Cav
- Leetcode# 110 Balanced Binary Tree