Interesting Permutation
[Link](Problem - I - Codeforces)
题意
给你长度为n的数列 h n h_n hn,这个数列的某一项 h i h_i hi是由某个原数列前 i i i项的最大值减去最小值的的结果,问你用 1 − n 1-n 1−n这些数字可以构造出多少个原数列 a n a_n an。
题解
首先发现 h 1 h_1 h1一定为零,从前往后看因为每次加入一个新的 a i a_i ai就会产生三种情况1. 使得最大值变大 2. 使得最小值变小 3.介于原来最大最小值之间,最大最小不变,因此发现 h n h_n hn一定是一个非严格递增数列,并且 h m a x = = n − 1 h_{max}==n-1 hmax==n−1。所以先排除不合法的情况,当合法以后我们考虑怎么去推这个合法原数列的方案数。
如果按照每一位可以放哪些数这样去思考是很困难的,因为只问你合法的方案数是多少,所以可以考虑用一种增量的方法来统计答案,假设第一个数为 x x x我们先不考虑 x x x的具体值只考虑一个相对大小,然后依次考虑 h 2 , h 3 , . . . , h n h_2,h_3,...,h_n h2,h3,...,hn,如果 h i > h i − 1 h_i>h_{i-1} hi>hi−1就说明 a i a_i ai可以是前 i i i个数里的最大值也可以是最小值,所以对答案的贡献就是乘2,相当于把一个可数轴上的区间向左或向右延申了,因此新增中间 h i − h i − 1 − 1 h_i-h_{i-1}-1 hi−hi−1−1个空位没有填,如果 h i = = h i − 1 h_i==h_{i-1} hi==hi−1就说明 a i a_i ai是介于最大最小值的这个区间里可填的数的一个,假设有 l e n len len个可选的,那么对答案的贡献就是乘len,然后因为选了一个所以len–。当这样把原数组的方案数推出来以后,发现每个合法的方案都确定了一个最开始的 x x x,因此可以不重不漏的统计答案。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1);
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n; bool ok = false;
for (int i = 0; i < n; i ++ ) {
cin >> a[i];
if (a[i] >= n || (i && a[i] == 0) || (!i && a[i]) || (i && a[i] < a[i - 1])) ok = true;
}
if (ok) {
cout << 0 << endl;
continue ;
}
LL res = 1, len = 0;
for (int i = 1; i < n; i ++ ) {
if (a[i] == a[i - 1]) res = (res * len) % mod, len --;
else {
res = (res * 2) % mod;
len += (a[i] - a[i - 1] - 1) % mod;
}
}
cout << res << endl;
}
return 0;
}