n <= 60w,∑n <= 200w,1s。c++
解:首先有個全排列 + 樹狀數組的暴力。數組
而後有個沒有任何規律的狀壓...首先我想的是按照大小順序來放數,能夠分爲肯定絕對位置和相對位置兩種,可是都很差處理字典序。dom
而後換個思路一位一位的考慮放哪一個數。用一維來記錄|i - pi| - 逆序對數 * 2,還有一維記錄是否緊貼下限,一個二進制數記錄以前填了哪些數。ide
當前填到哪一位能夠經過二進制中1的個數統計出來。這樣就是一個n32n的作法,能夠過n <= 14的點,獲得24分。ui
1 /** 2 * There is no end though there is a start in space. ---Infinity. 3 * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite. 4 * Only the person who was wisdom can read the most foolish one from the history. 5 * The fish that lives in the sea doesn't know the world in the land. 6 * It also ruins and goes if they have wisdom. 7 * It is funnier that man exceeds the speed of light than fish start living in the land. 8 * It can be said that this is an final ultimatum from the god to the people who can fight. 9 * 10 * Steins;Gate 11 */ 12 13 #include <bits/stdc++.h> 14 15 const int N = 600010, MO = 998244353; 16 17 int p[N], n; 18 19 inline void Add(int &a, const int &b) { 20 a += b; 21 while(a >= MO) a -= MO; 22 while(a < 0) a += MO; 23 return; 24 } 25 26 inline void out(int x) { 27 for(int i = 0; i < n; i++) { 28 printf("%d", (x >> i) & 1); 29 } 30 return; 31 } 32 33 namespace Sta { 34 const int DT = 500, M = 33000; 35 int f[DT * 2][M][2], cnt[M], pw[M]; 36 inline void prework() { 37 for(int i = 1; i < M; i++) { 38 cnt[i] = 1 + cnt[i - (i & (-i))]; 39 } 40 for(int i = 2; i < M; i++) { 41 pw[i] = pw[i >> 1] + 1; 42 } 43 return; 44 } 45 inline void solve() { 46 memset(f, 0, sizeof(f)); 47 f[DT][0][0] = 1; 48 /// DP 49 int lm = (1 << n) - 1, lm2 = n * (n - 1) / 2; /// lm : 11111111111 50 for(int s = 0; s < lm; s++) { 51 for(int i = -lm2; i <= lm2; i++) { 52 /// f[i + DT][s][0/1] 53 if(!f[i + DT][s][0] && !f[i + DT][s][1]) continue; 54 //printf("f %d ", i); out(s); printf(" 0 = %d 1 = %d \n", f[i + DT][s][0], f[i + DT][s][1]); 55 int t = lm ^ s; 56 while(t) { 57 int j = pw[t & (-t)] + 1, temp = i + std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] * 2 + DT, t2 = s | (1 << (j - 1)); 58 /// f[i + DT][s][1] -> f[std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] + DT][s | (1 << (j - 1))][1] 59 Add(f[temp][t2][1], f[i + DT][s][1]); 60 //printf("1 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]); 61 if(j > p[cnt[s] + 1]) { 62 Add(f[temp][t2][1], f[i + DT][s][0]); 63 //printf("0 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]); 64 } 65 else if(j == p[cnt[s] + 1]) { 66 Add(f[temp][t2][0], f[i + DT][s][0]); 67 //printf("0 > %d ", temp - DT); out(t2); printf(" 0 = %d\n", f[temp][t2][0]); 68 } 69 t ^= 1 << (j - 1); 70 } 71 } 72 } 73 74 printf("%d\n", f[DT][lm][1]); 75 return; 76 } 77 } 78 79 int main() { 80 //printf("%d \n", (sizeof(Sta::f)) / 1048576); 81 int T; 82 scanf("%d", &T); 83 Sta::prework(); 84 while(T--) { 85 scanf("%d", &n); 86 for(int i = 1; i <= n; i++) { 87 scanf("%d", &p[i]); 88 } 89 Sta::solve(); 90 } 91 return 0; 92 }
而後咱們必須開始找規律了......這裏我是徹底沒思路(太過SB)this
冷靜分析一波發現,一個合法的排列等價於一個不存在長度爲三的降低子序列的排列。spa
由於若是存在長度爲3的降低子序列,那麼中間那個元素必定有一次移動不是如它所想的。而不存在的話,咱們就能夠概括,冒泡排序每一步都會減小一對逆序對,降低子序列必定不會變長。(全是口胡,意會就好了)3d
而後有一個44分的狀壓DP出來了,我沒寫...code
80分n2DP,先考慮怎麼求答案。枚舉哪一個位置開始自由,若是在i開始自由的話就要知道後面有多少種填法。因此咱們須要一個從當前狀態到終態的狀態,而不是從初態到當前。blog
(看題解)發現若是前綴最大值爲j,那麼當前要麼填比j小的最小的,要麼填比j大的。由於若是填了比j小的又不是最小的,就會有一個長爲3的降低子序列。
而後設fi,j表示還剩i位要填,能填的數中比max(1~i)大的有j個,填滿的方案數。
因而有f[i][j] = ∑f[i - 1][k] = f[i][j - 1] + f[i - 1][j]
因而枚舉在哪自由,而後把對應的j求出來。每一個位置要加上fn-i,0~j-1
注意有兩個地方要break,一個是後面沒有比max(1~i)大的數了,還有就是當前填了長爲3的降低子序列了。
100分:發現f這個東西其實就是格路徑方案數......特別注意i < j的時候爲0,因此有一條線不能跨過......
組合數學一波,就能O(1)計算f了。而後發現這個東西fn-i,0~j-1不就是fn-i+1,j-1嗎?而後就完事了,nlogn。
1 /** 2 * There is no end though there is a start in space. ---Infinity. 3 * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite. 4 * Only the person who was wisdom can read the most foolish one from the history. 5 * The fish that lives in the sea doesn't know the world in the land. 6 * It also ruins and goes if they have wisdom. 7 * It is funnier that man exceeds the speed of light than fish start living in the land. 8 * It can be said that this is an final ultimatum from the god to the people who can fight. 9 * 10 * Steins;Gate 11 */ 12 13 #include <bits/stdc++.h> 14 15 typedef long long LL; 16 const int N = 600010, MO = 998244353; 17 18 int p[N], n; 19 int fac[N << 1], inv[N << 1], invn[N << 1]; 20 21 inline LL C(int n, int m) { 22 if(n < 0 || m < 0 || n < m) return 0; 23 return 1ll * fac[n] * invn[m] % MO * invn[n - m] % MO; 24 } 25 26 inline void Add(int &a, const int &b) { 27 a += b; 28 while(a >= MO) a -= MO; 29 while(a < 0) a += MO; 30 return; 31 } 32 33 inline void out(int x) { 34 for(int i = 0; i < n; i++) { 35 printf("%d", (x >> i) & 1); 36 } 37 return; 38 } 39 40 namespace Sta { 41 const int DT = 500, M = 33000; 42 int f[DT * 2][M][2], cnt[M], pw[M]; 43 inline void prework() { 44 for(int i = 1; i < M; i++) { 45 cnt[i] = 1 + cnt[i - (i & (-i))]; 46 } 47 for(int i = 2; i < M; i++) { 48 pw[i] = pw[i >> 1] + 1; 49 } 50 return; 51 } 52 inline void solve() { 53 memset(f, 0, sizeof(f)); 54 f[DT][0][0] = 1; 55 /// DP 56 int lm = (1 << n) - 1, lm2 = n * (n - 1) / 2; /// lm : 11111111111 57 for(int s = 0; s < lm; s++) { 58 for(int i = -lm2; i <= lm2; i++) { 59 /// f[i + DT][s][0/1] 60 if(!f[i + DT][s][0] && !f[i + DT][s][1]) continue; 61 //printf("f %d ", i); out(s); printf(" 0 = %d 1 = %d \n", f[i + DT][s][0], f[i + DT][s][1]); 62 int t = lm ^ s; 63 while(t) { 64 int j = pw[t & (-t)] + 1, temp = i + std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] * 2 + DT, t2 = s | (1 << (j - 1)); 65 /// f[i + DT][s][1] -> f[std::abs(cnt[s] + 1 - j) - cnt[s >> (j - 1)] + DT][s | (1 << (j - 1))][1] 66 Add(f[temp][t2][1], f[i + DT][s][1]); 67 //printf("1 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]); 68 if(j > p[cnt[s] + 1]) { 69 Add(f[temp][t2][1], f[i + DT][s][0]); 70 //printf("0 > %d ", temp - DT); out(t2); printf(" 1 = %d\n", f[temp][t2][1]); 71 } 72 else if(j == p[cnt[s] + 1]) { 73 Add(f[temp][t2][0], f[i + DT][s][0]); 74 //printf("0 > %d ", temp - DT); out(t2); printf(" 0 = %d\n", f[temp][t2][0]); 75 } 76 t ^= 1 << (j - 1); 77 } 78 } 79 } 80 81 printf("%d\n", f[DT][lm][1]); 82 return; 83 } 84 } 85 86 namespace Stable { 87 88 int ta[N]; 89 90 inline void add(int i) { 91 for(; i <= n; i += i & (-i)) ta[i]++; 92 return; 93 } 94 inline int ask(int i) { 95 int ans = 0; 96 for(; i; i -= i & (-i)) { 97 ans += ta[i]; 98 } 99 return ans; 100 } 101 inline void clear() { 102 memset(ta + 1, 0, n * sizeof(int)); 103 return; 104 } 105 106 inline bool check() { 107 int ans = 0, cnt = 0; 108 for(int i = n; i >= 1; i--) { 109 cnt += std::abs(i - p[i]); 110 ans += ask(p[i] - 1); 111 add(p[i]); 112 } 113 clear(); 114 return cnt == ans * 2; 115 } 116 117 inline int cal() { 118 int ans = 0; 119 for(int i = 1; i <= n; i++) { 120 if(p[i] < p[i - 1]) ans++; 121 } 122 return ans + 1; 123 } 124 125 inline void work() { 126 for(n = 1; n <= 10; n++) { 127 for(int i = 1; i <= n; i++) p[i] = i; 128 do { 129 if(check()) { 130 for(int i = 1; i <= n; i++) { 131 printf("%d ", p[i]); 132 } 133 } 134 else { 135 printf("ERR : "); 136 for(int i = 1; i <= n; i++) { 137 printf("%d ", p[i]); 138 } 139 } 140 printf(" cal = %d \n", cal()); 141 } while(std::next_permutation(p + 1, p + n + 1)); 142 getchar(); 143 } 144 return; 145 } 146 } 147 148 namespace DP { 149 const int M = 1010; 150 int f[M][M], ta[N]; 151 inline void add(int i) { 152 for(; i <= n; i += i & (-i)) ta[i]++; 153 return; 154 } 155 inline int ask(int i) { 156 int ans = 0; 157 for(; i; i -= i & (-i)) { 158 ans += ta[i]; 159 } 160 return ans; 161 } 162 inline int getSum(int l, int r) { 163 return ask(r) - ask(l - 1); 164 } 165 inline int F(int i, int j) { 166 if(i < j) return 0; 167 return (C(i + j - 1, j) - C(i + j - 1, i + 1) + MO) % MO; 168 } 169 inline void solve() { 170 /*memset(f, 0, sizeof(f)); 171 f[0][0] = 1; 172 for(int i = 1; i <= n; i++) { 173 for(int j = 0; j <= i; j++) { 174 f[i][j] = (f[i - 1][j] + f[i][j - 1]) % MO; 175 } 176 }*/ 177 178 /*for(int j = n; j >= 0; j--) { 179 for(int i = 0; i <= n; i++) { 180 printf("%3d ", f[i][j]); 181 } 182 puts(""); 183 }*/ 184 185 int ans = 0, pre = 0; 186 for(int i = 1; i < n; i++) { 187 /// [1, i - 1] == i > 188 pre = std::max(pre, p[i]); 189 int k = n - pre - getSum(pre + 1, n); 190 //printf("i = %d k = %d \n", i, k); 191 if(!k) break; 192 /*for(int j = 0; j < k; j++) { 193 Add(ans, F(n - i, j)); 194 //printf("add f %d %d \n", n - i, j); 195 }*/ 196 Add(ans, F(n - i + 1, k - 1)); 197 add(p[i]); 198 if(p[i] < pre && ask(p[i]) != p[i]) break; 199 } 200 printf("%d\n", ans); 201 memset(ta + 1, 0, n * sizeof(int)); 202 return; 203 } 204 } 205 206 int main() { 207 //printf("%d \n", (sizeof(Sta::f)) / 1048576); 208 //Stable::work(); 209 fac[0] = inv[0] = invn[0] = 1; 210 fac[1] = inv[1] = invn[1] = 1; 211 for(int i = 2; i < N * 2; i++) { 212 fac[i] = 1ll * fac[i - 1] * i % MO; 213 inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO; 214 invn[i] = 1ll * invn[i - 1] * inv[i] % MO; 215 } 216 int T; 217 scanf("%d", &T); 218 //Sta::prework(); 219 while(T--) { 220 scanf("%d", &n); 221 for(int i = 1; i <= n; i++) { 222 scanf("%d", &p[i]); 223 } 224 DP::solve(); 225 } 226 return 0; 227 }