BZOJ1925 [SDOI2010]地精部落
阿新 • • 發佈:2018-11-12
Description
傳送門
求\(N\)的排列中有多少個波動數列.
波動數列是指對於數列中的每一個數,他兩邊的數必須嚴格小於或大於自己.
\[ n \leq 4200, Mod \leq 1e9 \]
Solution
首先我們必須要搞清楚3個性質
- First: 在一個波動數列中,若兩個 i 與 i+1 不相鄰,那麼我們直接交換這兩個數字就可以組成一個新的波動數列; 舉個栗子: 5 2 3 1 4
4 2 3 1 5
- Second: 把波動數列中的每個數字Ai 變成 (N+1)-Ai 會得到另一個波動數列,且新數列的山峰與山谷情況相反;
舉個栗子: 1 4 2 5 3 (用 6 - 每個數) 1是山谷,4是山峰,後面類推
5 2 4 1 3 這個數列也是波動的 ,且 5是山峰,2是山谷;
- Third: 波動序列有對稱性。 栗子:1 4 2 5 3 to 3 5 2 1 4
(以上轉自luogu)
那麼我們設\(Dp[i][j]\)表示\(1\)到\(i\)的排列中, 當前數列首端為高度j
的山峰的方案數.
考慮如果j,j - 1不相鄰, 那麼直接交換就可以.即\(Dp[i][j - 1]\)
如果相鄰, 那麼顯然j - 1是山谷. 所以應用性質二,把山峰變成山谷,即:\(DP[i - 1][(i - 1 + 1) - (j - 1)] = DP[i - 1][i - j + 1]\)
所以答案為:\(DP[i][j] = DP[i][j - 1] + DP[i - 1][i - j + 1]\)
由於空間太小, 考慮滾動陣列優化.
Codes
#include<bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i) #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i) #define clar(a, b) memset((a), (b), sizeof(a)) #define debug(...) fprintf(stderr, __VA_ARGS__) #define Debug(s) debug("The massage in line %d, Function %s: %s\n", __LINE__, __FUNCTION__, s) typedef long long LL; typedef long double LD; const int BUF_SIZE = (int)1e6 + 10; struct fastIO { char buf[BUF_SIZE], buf1[BUF_SIZE]; int cur, cur1; FILE *in, *out; fastIO() { cur = BUF_SIZE, in = stdin, out = stdout; cur1 = 0; } inline char getchar() { if(cur == BUF_SIZE) fread(buf, BUF_SIZE, 1, in), cur = 0; return *(buf + (cur++)); } inline void putchar(char ch) { *(buf1 + (cur1++)) = ch; if (cur1 == BUF_SIZE) fwrite(buf1, BUF_SIZE, 1, out), cur1 = 0; } inline int flush() { if (cur1 > 0) fwrite(buf1, cur1, 1, out); return cur1 = 0; } }IO; #define getchar IO.getchar #define putchar IO.putchar int read() { char ch = getchar(); int x = 0, flag = 1; for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1; for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; return x * flag; } void write(int x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar(x % 10 + 48); } void putString(char s[], char EndChar = '\n') { rep(i, 0, strlen(s) - 1) putchar(*(s + i)); if(~EndChar) putchar(EndChar); } #define Maxn 4209 int n, p, dp[2][Maxn]; namespace INIT { void Main() { n = read(), p = read(); } } namespace SOLVE { void Main() { dp[1][1] = 1; rep(i, 2, n) rep(j, 1, i) dp[i & 1][j] = (dp[(i - 1) & 1][i - j + 1] + dp[i & 1][j - 1]) % p; int ans = 0; rep(i, 1, n) ans = (ans + dp[n & 1][i]) % p; ans = ans * 2 % p; write(ans), putchar('\n'); } } int main() { #ifdef Qrsikno freopen("BZOJ1925.in", "r", stdin); freopen("BZOJ1925.out", "w", stdout); #endif INIT :: Main(); SOLVE :: Main(); #ifdef Qrsikno debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC); #endif return IO.flush(); }