#NOIP模拟赛#排列问题(DP)
2017-08-19 21:30
274 查看
这个题,是一个DP,令人惊讶,我当时根本就没往这方面想,还是题见得少了
同学有一个DP解法,个人感觉比标解好理解得多,具体如下:
如图:
将数字1 ~ N从大到小填
定义Dp[full][half][sum]表示
已经填了full个格子(上下对应都填了, 如:上4下5)
有2 * half个格子填了一半(如:红色点的两个格子,由于这种格子必然是偶数个,所以除2)
已经填的数的总和是sum
Dp值是此时的方案数。
这题的转移有三种情况,
以上图为例,现在应该填now = 3:
1,分别填在两个蓝色格子内,并使他们无法组成一个新的full,此时有N - full - (half - 1) * 2个上下同时为空的格子,所以:
Dp[full][half][sum] += Dp[full][half - 1][sum - 2 * now] * (N - full - (half - 1) * 2) * (N - full - (half - 1) * 2 - 1) % MOD;
2,使成为一个新的full(直接填在一对对应的空格子里(蓝色), 或者填一个在红色格子里,再填一个在蓝色格子里,half值不变,将损失1对full):
Dp[full][half][sum] += Dp[full - 1][half][sum - now] * (half * 2 * (N - half *2 - (full - 1)) + N - half * 2 - (full - 1));
3,使成为一个新的full(填在两个半格里(红色),将损失1对half):
Dp[full][half][sum] += Dp[full - 2][half + 1][sum] * (half + 1) * (half + 1);
最后的答案是 Σ Dp
[0][sum](sum >= K)
下面是标解,和上面的解法有所不同:
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int MOD = 1e9 + 7;
int N, K, L, Ans;
int Dp[55][55][55 * 55];
bool getint(int & num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9'){
if(c == '-') flg = -1;
if(c == -1) return 0;
}
while(c >= '0' && c <= '9'){
num = num * 10 + c - 48;
if((c = getchar()) == -1) return 0;
}
num *= flg;
return 1;
}
int P(int x){
int rt = 1;
for(int i = 2; i <= x; ++ i)
rt = 1ll * rt * i % MOD;
return rt;
}
int main(){
freopen("data1.in", "r", stdin);
//freopen("permutation.in", "r", stdin);
//freopen("permutation.out", "w", stdout);
getint(N), getint(K);
int up = N * N;
Dp[0][0][0] = 1;
for(int i = 1; i <= N; ++ i){
int now = N - i + 1;
for(int full = 0; full <= i; ++ full){
int half = i - full;
for(int s = 0; s <= up; ++ s){
if(s >= now * 2 && N - full - (half - 1) * 2 > 0)
Dp[full][half][s] = (Dp[full][half][s] + 1ll*Dp[full][half-1][s-(now << 1)]*(N-full-((half-1)<<1))%MOD*(N-full-((half-1)<<1)-1)%MOD)%MOD;
if(full && s >= now)
Dp[full][half][s] = (Dp[full][half][s] + 1ll*Dp[full-1][half][s-now]*((half*(N-(half<<1)-(full-1))<<1)%MOD+N-(half<<1)-(full-1))%MOD)%MOD;
if(full >= 2)
Dp[full][half][s] = (Dp[full][half][s] + 1ll*Dp[full-2][half+1][s]*(half+1)%MOD*(half+1)%MOD)%MOD;
}
}
}
int Ans = 0;
for(int i = K; i <= up; ++ i)
Ans = (Ans + Dp
[0][i]) % MOD;
printf("%d\n", Ans);
return 0;
}
相关文章推荐
- NYOJ 469 擅长排列的小明 II (dp问题)
- 【XSY2666】排列问题 DP 容斥原理 分治FFT
- light oj 1021 - Painful Bases(状压DP解决全排列余数为定值的问题)
- 排列问题(DP)
- 【dp】有向直线k中值问题
- 全排列问题
- 全排列问题
- 递归--【全排列问题】九度1459.Prime ring problem
- 桌面右键菜单的“排列图标”和“新建”选项丢失问题
- abc排列问题
- poj 1294 全排列问题
- HDU 6143 排列组合 - DP
- HDU 4529 郑厂长系列故事——N骑士问题(状态压缩DP)
- Hrbust Online Judge 排列问题
- 递归-排列问题
- 树(prufer序,dp,排列组合)
- 重叠子问题+状压DP(位压缩)(1074)
- 排列组合问题的通用算法
- 牛客练习赛7 购物 DP 初始化问题
- 多柱(m柱)汉诺塔问题 解题报告【DP】