CFgym102394I - Interesting Permutation
题目
DreamGrid has an interesting permutation of \(1,2,...,n\) denoted by \(a_1,a_2,...a_n\).
- For each \(1 \le i \le n\), \(f_i = \max\{a_1,a_2...,a_i\}\).
- For each \(1 \le i \le n\), \(g_i = \min\{a_1,a_2...,a_i\}\).
- For each \(1 \le i \le n\), \(h_i = f_i - g_i\).
Given the sequence h, please calculate the number of different permutations that can generate the sequence h. Print the answer modulo \(10^9+7\).
思路
一开始想歪想复杂了。\(h_i\)代表最大值和最小值之间的差值,这个差值代表可以选择的数字数。维护一个可选数字数cnt。当\(h_i > h_{i-1}\),说明当前位是前缀的最大值或最小值,所以\(ans=2\times ans\),\(cnt = cnt + (h_i - h_{i-1} - 1)\);当\(h_i == h_{i-1}\),说明当前位置可以选一个数字放进去,所以\(ans=cnt\times ans\),\(cnt = cnt - 1\)。
一开始特判一些不合法的情况,然后就可以求解了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
const int M = 1e9 +7;
#define endl '\n'
int h[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--) {
int n;
cin >> n;
bool ok = true;
for(int i = 1; i <= n; i++) {
cin >> h[i];
if(i > 1 && h[i] < h[i - 1] || h[i] >= n) ok = false;
}
if(h[1] != 0) ok = false;
else if(h[n] != n - 1) ok = false;
else if(n > 1 && h[2] == 0) ok = false;
if(!ok) cout << 0 << endl;
else {
int cnt = 0;
ll ans = 1;
for(int i = 2; i <= n; i++) {
if(h[i] > h[i - 1]) {
cnt += h[i] - h[i - 1] - 1;
ans = ans * 2 % M;
} else {
ans = ans * cnt % M;
cnt--;
}
}
cout << ans << endl;
}
}
}