您的位置:首页 > 产品设计 > UI/UE

Uestc ABCDE 1037

2016-04-13 15:59 429 查看
好久不写题解。。。

给定一个数n,求有多少个集合满足能够构成1到n的所有数字。具体规则看题

思路:

很明显是要n^2预处理出所有的情况

但是状态不好搞啊==

现场时这个dp没有想出来

dp的关键是要解决如何能保证在dp转移的时候同时满足这个能构成n的所有数字的条件

对于这种条件有个性质要知道,表示这个性质已经不是第一次遇见了。。。。

对于一个已经满足条件的集合x,集合元素之和为s,再加上一个数字能满足这个条件的,这个数字的最大值为 s/2+s&1

dp方程的构建就是按照这样来的,还有一点要注意就是对于前缀和这个东东在dp中的运用,很多dp的中等以上的题都要用到这个



代码如下
/*  ^^ ====== ^^
ID: meixiuxiu
PROG: test
LANG: C++11
*/
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <sstream>
#include <cctype>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int ,int> pii;
#define MEM(a,b) memset(a,b,sizeof a)
#define CLR(a) memset(a,0,sizeof a);
#define pi acos(-1.0)
#define maxn 40000
#define maxv 100005
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
//#define LOCAL
ll dp[5005][5005];
ll sum[5005];
void init(){
dp[1][0]=1;
for(int i=1;i<=5000;i++){
for(int j=1;j<=i+1;j++){
dp[i][j] = (dp[i][j-1]+dp[i][j])%MOD;
int l = j,r = i+j+2;
if(l+i+j<=5000)dp[i+j][l] = (dp[i+j][l]+dp[i][j])%MOD;
if(r+i+j<=5000)dp[i+j][r] = (dp[i+j][r]-dp[i][j])%MOD;
}
}
sum[1] = 1;
for(int i=1;i<=5000;i++){
for(int j=1;j<=i+1;j++){
if(i+j<=5000)sum[i+j] = (sum[i+j]+dp[i][j])%MOD;
}
}
}
int main()
{
#ifdef LOCAL
//freopen("in.txt", "r", stdin);
//	freopen("out.txt","w",stdout);
#endif
init();
int t;cin >> t;
while(t--){
int a;cin >> a;
printf("%lld\n",sum[a]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: