poj2279 Mr. Young's Picture Permutations[勾长公式 or 线性DP]

若干人左对齐站成最多5行,给定每行站多少个,列数从第一排开始往后递减。要求身高从每排从左到右递增(我将题意篡改了便于理解233),每列从前向后递增。每个人身高为1...n(n<=30)中的一个数(互不不同)。求可行方案数。(地址点我qwq);



做了lyd书dp这一章的第一题,就不会qwq。。果然菜的人还是永远菜啊,注定翻不了身。

lyd的书上讲到了dp的方法,不是很理解。后来想通了,发现自己想的时候也想到了这一点转化,但是又很快把他抛弃掉了。。冏。

上面所谓的转化就是说,我本来安排人去排列,是无序的,显然也不好dp,因为高度不定,选了哪些也不知道,对后续状态有影响,所以要转化为有序的dp。有没有觉得很熟悉?BZOJ1079[SCOI2008]着色方案[组合计数DP]这里就是将无序的排列改为有序的插入。

对于要求从前面的一些状态中有条件限制的转移,当条件不易表达时,尝试将无序选择转化为有序的顺次选择简化之。

为什么顺序插入身高是对的?假设我已经插入$i$个身高最矮的人,那么身高$i+1$的人除了插入每一行的末尾别无选择,试想如果插在排好的队中,显然不单调。和末尾空了一格或多格站,那么中间就找不到合适身高的人站进去了。当然也要保证插入的行的当前人数少于上一行的,不然上一行会比这一行少空位,之后身高更高的人也没办法站上去。这样做完,就可以保证排列方案满足要求。有没有什么方案不能通过上面这种方案构造出来的?没有,因为不按上面那种插入的话,其他情况必然无解。所以对于每一种可行方案,我可以认为他是按从小到大身高顺序每个依次在某一行末尾插入的得到的。那么我就可以顺理成章设f[a][b][c][d][e]来记录状态了,然后就是lyd书上的做法。对于每个状态,去推出其他可以拓展的后续状态(在这题也就是再插入身高排名下一位的人)。

实现上dp数组开满会爆内存,可以采用动态开数组(说白了就是主函数内部根据大小开数组),或者f[31][16][11][8][7]也可以,为什么您们都看得出来。。然而前者速度吊打后者,因为是动态开的嘛,后者每次还要全部清空。

其他一些细节(比如不满5行怎么办)看code,也可以照例解决,就把空的几行看成数组下标是0即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl
 8 #define ddbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
 9 using namespace std;
10 typedef long long ll;
11 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
12 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
15 template<typename T>inline T read(T&x){
16     x=0;int p=0;char c;while(!isdigit(c=getchar()))if(c==‘-‘)p=1;
17     while(isdigit(c))x=x*10+(c&15),c=getchar();return p?x=-x:x;
18 }
19 int x[6];
20 int n;
21 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
22     while(read(n),n){
23         memset(x,0,sizeof x);
24         for(register int i=1;i<=n;++i)read(x[i]);
25         unsigned int f[x[1]+2][x[2]+2][x[3]+2][x[4]+2][x[5]+2];
26         memset(f,0,sizeof f);
27         f[0][0][0][0][0]=1;
28         for(register int a=0;a<=x[1];++a)
29             for(register int b=0;b<=x[2];++b)
30                 for(register int c=0;c<=x[3];++c)
31                     for(register int d=0;d<=x[4];++d)
32                         for(register int e=0;e<=x[5];++e){
33                             f[a+1][b][c][d][e]+=f[a][b][c][d][e];
34                             if(b<a)f[a][b+1][c][d][e]+=f[a][b][c][d][e];
35                             if(c<b)f[a][b][c+1][d][e]+=f[a][b][c][d][e];
36                             if(d<c)f[a][b][c][d+1][e]+=f[a][b][c][d][e];
37                             if(e<d)f[a][b][c][d][e+1]+=f[a][b][c][d][e];
38                         }
39         printf("%u\n",f[x[1]][x[2]][x[3]][x[4]][x[5]]);
40     }
41     return 0;
42 }

poj2279 Mr. Young's Picture Permutations[勾长公式 or 线性DP]

原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10656443.html

时间: 2024-11-07 07:58:44

poj2279 Mr. Young's Picture Permutations[勾长公式 or 线性DP]的相关文章

线性DP POJ2279 Mr.Young&#39;s Picture Permutations

Mr. Young's Picture Permutations Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1128   Accepted: 562 Description Mr. Young wishes to take a picture of his class. The students will stand in rows with each row no longer than the row behin

[POJ2279] Mr.Young&#39;s Picture Permutations

歪解:爆空间的DP //Writer:jr HSZ;%%%WJMZBMR #include<iostream> #include<cstdio> #include<cstring> #define LL long long #define reg register int #define f(i,a,b) for(reg i=a;i<=b;i++) using namespace std; int n,sum; int a[6]; LL f[31][31][31]

【题解】POJ2279 Mr.Young′s Picture Permutations dp

[题解]POJ2279 Mr.Young′s Picture Permutations dp 钦定从小往大放,然后直接dp. \(dp(t1,t2,t3,t4,t5)\)代表每一行多少人,判断边界就能dp. 然后你发现\(30^5\)开不下,但是你仔细观察由于它保证\(\sum < 30\)所以你只用开\(30^5 \div 5!\)就好了. 具体为什么我相信你会 //@winlere #include<iostream> #include<cstring> #include

【杨氏矩阵+勾长公式】POJ 2279 Mr. Young&#39;s Picture Permutations

Description Mr. Young wishes to take a picture of his class. The students will stand in rows with each row no longer than the row behind it and the left ends of the rows aligned. For instance, 12 students could be arranged in rows (from back to front

poj2533——lis(最长上升子序列), 线性dp

poj2533——lis(最长上升子序列), 线性dp Longest Ordered Subsequence Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 36143   Accepted: 15876 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given n

SP15637 GNYR04H - Mr Youngs Picture Permutations

传送门 Description 杨先生希望为他的班级拍照.学生将排成一行,每行不超过后面的行,并且行的左端对齐.例如,可以安排12名学生排列(从后到前)5,3,3和1名学生. X X X X X X X X X X X X 此外,杨先生希望每排学生安排高度从左到右减少.此外,学生身高应从后向前减少.想想看,杨先生看到,对于这个12人的例子,至少有两种安排学生的方式(数字代表高度,其中1代表最高): 1 2 3 4 5 1 5 8 11 12 6 7 8 2 6 9 9 10 11 3 7 10

公式推导 圆面积公式 圆周长公式

圆面积公式把圆平均分成若干份,可以拼成一个近似的长方形.长方形的宽就等于圆的半径(r),长方形的长就是圆周长(C)的一半.长方形的面积是ab,那圆的面积就是:圆的半径(r)乘以二分之一周长C,S=r*C/2=r*πr.圆周长公式圆周长(C):圆的直径(d),那圆的周长(C)除以圆的直径(d)等于π,那利用乘法的意义,就等于 π乘以圆的直径(d)等于圆的周长(C),C=πd.而同圆的直径(d)是圆的半径(r)的两倍,所以就圆的周长(C)等于2乘以π乘以圆的半径(r),C=2πr.

最长上升子序列--经典dp

最长上升子序列 Time Limit: 3000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1<= i1 < i2 < ... < iK <= N.比如,对于序列(1, 7, 3, 5, 9, 4, 8)

nyoj 36 最长公共子序列 【DP】

今天听了老师讲的最长公共子序列,就拿以前做过的题又做了一遍... 我用的是最简单普通的方法, 代码: #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int dp[1005][1005]; int main() { char a[1005], b[1005]; int t; scanf("%d", &t); while(t --){ s