1. 程式人生 > 其它 >CF1677 D Tokitsukaze and Permutations

CF1677 D Tokitsukaze and Permutations

CF1677 D Tokitsukaze and Permutations

傳送門:https://codeforc.es/contest/1677/problem/D

官方題解:https://codeforc.es/contest/1677/attachments/download/16092/Codeforces Round 789 Chinese Tutorial.pdf


考慮一個未進行過操作的排列 \(P\),以及其 \(v\) 序列。

定義一個 \(v\) 序列合法,當且僅當存在至少一個 \(P\) 與其對應。

容易發現 \(P\)\(v\) 其實是一一對應的。

證明:

給定一個 \(P\) 陣列,我們能根據定義求出唯一一個 \(v\)

給定一個合法 \(v\) 陣列,顯然我們能通過 \(v_n\) 知道 \(P_n\) 的值,然後就能通過 \(v_{n-1}\) 知道 \(P_{n-1}\) 的值。以此類推,我們能夠確定 \(P\)

得證。

所以我們可以直接對 \(v\) 進行計數。

同樣的我們考慮怎樣的 \(v\) 序列是合法的。不難發現如果對於任意 \(v_i\)\(v_i<i\)。那麼 \(v\) 是合法的。

證明:

\(v\) 的長度為 \(1\) 時顯然成立。

假設當 \(v\) 的長度為 \(n-1\) 時成立。設 \(v\) 是一個長為 \(n\) 的序列,\(P\) 是一個長為 \(n-1\)

的序列,且與 \(v\) 的前 \(n-1\) 項構成的 \(v'\) 對應。

\(v_n\ge n\) 時,顯然不合法,當 \(v_n<n\) 時,我們將 \(v_n+1\) 這個數放到 \(P_n\)。然後將 \(n\) 這個數放在 \(P\)\(n-1\) 這個數的位置,將 \(n-1\) 放到 \(n-2\) 的位置,以此類推。我們得到了一個新的序列 \(P'\)

顯然 \(P'\)\(v\) 對應。

證畢。

因此我們可以考慮對 \(v\) 計數。

我們發現進行一次操作就是相當於對原序列做一次氣泡排序。

觀察 \(v\) 的變化。發現 \(v\) 序列的變化相當於先使 \(v_i=\max(v_i-1,0)\)

,再將整個 \(v\) 序列左移,讓 \(v_1\) 直接被覆蓋,\(v_n\) 等於 \(0\)

\(V\) 為輸入的 \(v\) 序列。\(v\) 為我們計數的序列。

顯然 \(v_i,i\in[1,k]\) 的取值有 \(i\) 種可能,是 \([0,i-1]\)

對於 \(v_i,i\in[k+1,n]\)。如果 \(V_{i-k}=-1\)\(v_i\) 的取值有 \(i\) 種,如果 \(V_{i-k}=0\)\(v_i-k\le 0\)。所以 \(v_{i}\) 取值有 \(k+1\) 種。而當 \(0<V_{i-k}< i+k\) 時,\(v_i\) 取值確定。當 \(V_{i-k}\ge i-k\) 時,則滿足條件的 \(v\) 序列不存在。

對於 \(V_i,i\in[n-k+1,n]\),如果 \(V_i\) 不等於 \(0\)\(-1\)。則滿足條件的 \(v\) 序列也不存在。

將所有 \(v\) 序列可能取值的情況數相乘即可。

複雜度 \(O(n)\)

程式碼如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1e6+5;
const int MOD = 998244353;
int n,k,V[MAXN];
int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d",&n,&k);
		for(int i=1;i<=n;++i) scanf("%d",&V[i]);
		ll Ans=1;
		for(int i=1;i<=k;++i) Ans=Ans*i%MOD;
		for(int i=k+1;i<=n;++i)
		{
			if(V[i-k]==0) Ans=Ans*(k+1)%MOD;
			if(V[i-k]==-1) Ans=Ans*i%MOD;
			if(V[i-k]>=i-k) Ans=0;
		}
		for(int i=n-k+1;i<=n;++i) if(V[i]!=0&&V[i]!=-1) Ans=0;
		printf("%lld\n",Ans);
	}
	return 0;
}