Codeforces Round #789 (Div. 2) F. Tokitsukaze and Permutations
链接
题意:给出序列c,代表第i位之前有
c
i
c_i
ci个比他大的数字,如果是-1就是不知道,现在进行k次操作,每次操作如果
a
i
>
a
i
+
1
a_i > a_{i+1}
ai>ai+1,就交换这两个数字,直到最后一个,类似冒泡排序,求有多少个排列进行k次操作之后,他的
v
i
v_i
vi和给你的
v
i
v_i
vi是相同的。
思路:因为会进行k次冒泡排序,所有有k个数字可以随意选择,对1~k先进行一次累乘统计答案,并且我们先设初始状态为v,得出每次冒泡排序之后会使得每个位置的
v
i
v_i
vi减一然后左移覆盖,因为冒泡会使得最前面的数字一直交换到最后他比后面所有的都小,所以v会减1,并且左移。
然后还有一个我们可以得出的结论就是对于最后的c,所有确定的c可以确定唯一的数组元素,只有-1会发生变化,因为从后往前看,那这个数字就是现在的第
c
n
+
1
c_n+1
cn+1大,而对于-1的情况,它可以是任意的1~i,所以根据我们的结论:
我们可以根据当前的v确定初始状态,因为对于最后的k个是排过序了,我们只需要讨论
1
∼
n
−
k
1\sim n-k
1∼n−k,对于当前位置,如果是-1,他初始在i+k,所以他就有i+k种选择,我们乘上i+k。如果是1,则唯一确定,如果是0,则它就有k+1种选择,因为它可以是仍以的数字减去k得到的0
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 998244353;
int a[1000010];
signed main()
{
int T;
cin >> T;
while (T--) {
int n, k;
cin >> n >> k;
int f = 0;
for (int i = 1; i <= n; i++) {cin >> a[i]; if (a[i] > i - 1) f = 1;}
for (int i = n - k + 1; i <= n; i++) {
if (a[i] > 0) {f = 1; break;}
}
if (f) {cout << 0 << endl; continue;}
int ans = 1;
for (int i = 1; i <= k; i++) ans = (ans * i) % MOD;
for (int i = 1; i <= n - k; i++) {
if (a[i] == -1) {
ans = (ans * (i + k)) % MOD;
}else {
if (a[i]) {
if (a[i] + k > i - 1 + k) {f = 1; break;}
}else {
ans = ans * (min(k + 1, i + k)) % MOD;
}
}
}
if (f) {cout << 0 << endl; continue;}
cout << ans << endl;
}
return 0;
}