【BZOJ】1925: [Sdoi2010]地精部落 DP+滚动数组
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1925
题意:输入一个数N(1 <= N <= 4200),问将这些数排列成折线型有多少中合法的排列;折线形即一个数比相邻的数都大或者都小;
如:1 3 2 4就是一个折线型;
思路:f[i,j]表示排列的前i个数是以1...j为开头的第一位下降的合法个数;
转移公式为:f[i][j] = f[i][j-1] + f[i-1][i-j]; f[i][j-1]就不把第j个数添加到首位的原来的个数值;f[i-1][i-j]是当j为第一位时,由于第一位要是下降的,所以第二位要小于j,同时第二位还要是递增的;由于递增和递减的对称性,我们可以转而求第二位大于j,并且第二位是递减的。这样大于j的个数就是i-j,从第二位开始的递减就是 i-1个数;即f[i-1][i-j];
实现细节:至于滚动数组就是节约内存,之和前一个[i-1]这一维有关,即只用第一维开成2即可;最后还要*2,由于是对称的;但是需特判n = 1;
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define rep0(i,l,r) for(int i = (l);i < (r);i++) #define rep1(i,l,r) for(int i = (l);i <= (r);i++) #define rep_0(i,r,l) for(int i = (r);i > (l);i--) #define rep_1(i,r,l) for(int i = (r);i >= (l);i--) #define inf 0x7fffffff #define pow(a) (a)*(a) typedef long long ll; template<typename T> void read1(T &m) { T x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} m = x*f; } template<typename T> void read2(T &a,T &b){read1(a);read1(b);} template<typename T> void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);} #define N 4204 int dp[2][N]; int main() { int n,mod; read2(n,mod); if(n == 1) return puts("1"),0; int pre = 1,cur = 0; dp[pre][1] = 1; for(int i = 2;i <= n;i++){ pre ^= 1,cur ^= 1; for(int j = 1;j <= n;j++){ dp[pre][j] = dp[pre][j-1]; if(i >= j) dp[pre][j] += dp[cur][i-j]; if(dp[pre][j] > mod) dp[pre][j] -= mod; } } printf("%d\n",(dp[pre][n]*2)%mod); return 0; }