F. Tokitsukaze and Permutations
题意:
给你长度为n ( n ≤ 1 0 6 ) n(n\leq10^6)n(n≤106)的排列,可以进行k ( k < n ) k(k<n)k(k<n)次操作,每次操作从1 11遍历到n nn,如果a i > a i + 1 a_i>a_{i+1}ai>ai+1,则交换两个数字。
给你数组v ( v i < i ) v(v_i<i)v(vi<i),v i v_ivi表示a 1 ∼ a i − 1 a_1\sim a_{i-1}a1∼ai−1中小于a i a_iai的数字的数量
,如果v i = − 1 v_i=-1vi=−1,说明这个地方的结果丢失,可以是任意的值,问有多少种可能的排列,在k kk次交换后,可以得到数组v vv,答案对998244353 998244353998244353取模。
思路:
首先,对于任意一种构造的v vv,只要能够满足v i < i v_i<ivi<i,都有且只有一种排列能与之对应。
也就是说,只要我们能够任意构造出来不同的v vv,就会有与之对应的排列能够匹配,那么这样的构造有n ! n!n!种,但是其中有没有不合法的情况呢?
观察这种操作发现这个操作其实是冒泡排序中的一个回合,在操作完k kk个回合后,可以保证最后的k kk个数字一定已经按序归位,且是排列中最大的k kk个数字,在这种情况下v n − k + 1 ∼ v n v_{n-k+1}\sim v_nvn−k+1∼vn的值只能是0 00,所以刚才的构造不够合理。
只要有v n − k + 1 ∼ v n v_{n-k+1}\sim v_nvn−k+1∼vn的值不为0 00或− 1 -1−1,此序列一定无解。
此外还可以发现,每次操作一次,都会使所有的v i = m a x ( 0 , v i − 1 ) v_i=max(0,v_i-1)vi=max(0,vi−1),然后左移一格,将第一格直接覆盖掉,将v n = 0 v_n=0vn=0
考虑每个格子有多少种情况,总乘积就是我们的答案
操作k kk次,就会直接覆盖掉前k kk格,所以前k kk格不管填什么都没有影响,贡献是k ! k!k!
接下来是后面的格子,定义V VV为排列的v vv,v i = m a x ( V i + k − k , 0 ) v_i=max(V_{i+k}-k,0)vi=max(Vi+k−k,0)
若v i v_ivi大于0 00,则我们确定V i + k = v i + k V_{i+k}=v_i+kVi+k=vi+k结果唯一
若v i = 0 v_i=0vi=0,则V i + k V_{i+k}Vi+k可以是0 ∼ k 0\sim k0∼k贡献为k + 1 k+1k+1
若v i = − 1 v_i=-1vi=−1,无法判断,我们只要让v i < i v_i<ivi<i即可,贡献为i ii
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
int a[maxn];
ll mod=998244353;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,k;scanf("%d%d",&n,&k);
int ok=1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(i>=n-k+1 && a[i]>0) ok=0;
}
if(!ok)
{
puts("0");continue;
}
ll ans=1;
for(int i=k+1;i<=n;i++)
{
if(a[i-k]==0) ans=(ans*(k+1))%mod;
else if(a[i-k]==-1) ans=(ans*i)%mod;
}
for(int i=1;i<=k;i++) ans*=i,ans%=mod;
printf("%lld\n",ans);
}
}