CF1909F1 Small Permutation Problem (Easy Version) 题解
直接莽做显然不好统计。考虑统计每一次 \(i\) 的变化有多少种方案数来匹配,也就是对 \(a\) 数组差分。
考虑到对于 \(a_i\),只有 \([1,i]\) 里的数会对 \(a_i\) 有影响。注意到 \(p\) 形成一个排列,于是我们不妨考虑此时 \(p\) 中 \([1,i]\) 的贡献。
我们记 \(d=a_i-a_{i-1}\)。
- 若 \(d=0\),\(p_i>i\)。此时 \([1,i]\) 中不变化,答案不变。
- 若 \(d=1\),可能是 \(i\) 这个数填在 \(1\sim i-1\) 中未填的位置上或 \([1,i]\) 中有数字填在位置 \(i\) 上。未填的位置有 \(i-1-a_{i-1}\) 个,剩余的数字还有 \(i-a_{i-1}\) 个,二者相加就是方案数系数。
- 若 \(d=2\),一定是 \(i\) 填在 \(1\sim i-1\) 未填的位置上或 \([1,i-1]\) 中有数字填在位置 \(i\) 上。于是方案数的系数就是 \((i-a_{i-1}-1)^2\)。
- 若 \(d>2\),显然无解,输出
-1
即可。
注意加上一些不合法情况的特判即可。
代码:
#include <bits/stdc++.h>
#define N 200005
#define mod 998244353
#define int long long
using namespace std;
int T;
int n;
int a[N];
int solve() {
if (a[1] > 1 || a[n] != n) return 0;
int ans = 1;
for (int i = 1; i <= n; i++) {
int p = a[i] - a[i - 1];
if (p == 0) continue;
else if(p == 1) ans = ans * (i - a[i - 1] + i - 1 - a[i - 1]) % mod;
else if(p == 2) ans = ans * (i - 1 - a[i - 1]) % mod * (i - 1 - a[i - 1]) % mod;
else return 0;
}
return ans;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
cout << solve() << "\n";
}
return 0;
}
标签:int,题解,CF1909F1,Version,Easy,define
From: https://www.cnblogs.com/Rock-N-Roll/p/18548733