AT_arc149_e 题解
AT_arc149_e
思路
好题,在和 @Bellala 老师的讨论下懂了。
首先看题目,考虑对于一个初始序列
观察到,在第
如果操作数不足
现在只需要考虑
这时候在第
考虑转换成计数。
首先考虑无解的情况,因为你能够得知操作集合的位置了,而操作集合在原最终序列中的体现一定是升序的。所以只要不是,就无解。
然后,考虑新最终序列上的每一个数
最后在乘上一个最大
总结
可以固定一个动的位置来观测过程。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5 + 10;
const ll P = 998244353;
int n, m, K, b[N];
int tmp[N];
int main() {
scanf("%d%d%d", &n, &m, &K);
for (int i = 0; i < n; i++) scanf("%d", b + i);
if (K < n - m + 1) {
n = n - (n - m + 1 - K);
for (int i = 0; i < n; i++) tmp[i] = b[i];
sort(tmp, tmp + n);
int cnt = unique(tmp, tmp + n) - tmp;
for (int i = 0; i < n; i++) b[i] = lower_bound(tmp, tmp + cnt, b[i]) - tmp + 1;
}//离散化
int st = K % n, rev = K % (n - m + 1);
rotate(b, b + st, b + n);
//还原最后多余的操作
rotate(b + m - 1, b + n - rev, b + n);
//构建模型,其中前 m-1 个是操作集合,后面是新序列
ll ans = 1;
for (int i = 0; i < m - 1; i++) {
if (b[i] != n - m + i + 2) {
printf("0\n");
return 0;
}//无解
ans = ans * (i + 1) % P;
}
int mx = 0;
for (int i = m - 1; i < n; i++) {
if (b[i] > mx) {
mx = b[i];
ans = ans * m % P;
}
}
printf("%lld\n", ans);
return 0;
}
// AT_arc149_e