CodeForces 1677D Tokitsukaze and Permutations
还不错的一道思维 + 计数题。
思路
考虑一次操作后对 \(v\) 数组的影响:相当于将 \(v\) 数组左移一位,原本的 \(v_1\) 被覆盖了,\(v_n\) 补零,然后对于 \(i \in [1,n-1]\),\(v_i \gets \min(v_i - 1, 0)\)。同时还可以发现一个 \(v\) 数组对应着唯一一个排列。
考虑无解的情况:\(v\) 的后 \(k\) 位不是 \(0\),或者存在 \(i \in [1,n]\) 使得 \(v_i \ge i\)。特判掉即可,
接下来考虑对原来排列的 \(v'\) 计数(计算 \(v'\) 就相当于计算原来的 \(p\))。首先因为前 \(k\) 位被覆盖了,所以对于 \(i \in [1,k]\),\(v'_i\) 取 \([0,i-1]\) 的任意整数皆可。对于 \(i \in [k+1,n]\) 的 \(v'_i\):
- 如果 \(v_{i-k} = -1\),那么 \(v'_i\) 可以取 \([0,i-1]\) 的任意整数。
- 如果 \(v_{i-k} = 0\),那么 \(v'_i\) 可以取 \([0,k]\) 的任意整数。
- 如果 \(v_{i-k} > 0\),那么 \(v'_i\) 就确定了,为 \(v_{i-k} + k\)。
乘法原理计算即可。
代码
code
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const int maxn = 1000100;
const ll mod = 998244353;
ll n, m, a[maxn];
void solve() {
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
for (int i = 1; i <= n; ++i) {
if (a[i] >= i) {
puts("0");
return;
}
}
for (int i = n - m + 1; i <= n; ++i) {
if (a[i] > 0) {
puts("0");
return;
}
}
ll ans = 1;
for (int i = 1; i <= m; ++i) {
ans = ans * i % mod;
}
for (int i = m + 1; i <= n; ++i) {
if (a[i - m] == -1) {
ans = ans * i % mod;
} else if (a[i - m] == 0) {
ans = ans * (m + 1) % mod;
}
}
printf("%lld\n", ans);
}
int main() {
int T = 1;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}