CodeForces 1677D Tokitsukaze and Permutations

洛谷传送门

CF 传送门

还不错的一道思维 + 计数题。

思路

考虑一次操作后对 \(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;
}
posted @ 2022-07-11 15:51  zltzlt  阅读(39)  评论(0编辑  收藏  举报