1. 程式人生 > >[CF1091D]New Year and the Permutation Concatenation

[CF1091D]New Year and the Permutation Concatenation

 

link

題目大意

給$n!$個$n$的排列,按字典序從小到大連成一條序列,例如$3$的情況為:$[1,2,3, 1,3,2, 2,1,3 ,2,3,1 ,3,1,2 ,3,2,1]$,問其中長度為$n$,且和為$sum=n\times (n+1)/2$的序列有多少個?

試題分析

對於合理的序列有兩種情況,第一種是就是排列的,第二種就是前面$k$個與後面的$n-k$的一塊組成。

對於第一種情況,答案只要$n$個,所以我們只考慮第二種情況。

當$n=3$時,$n\times n!=3!\times 3\text{=}18$

而直接生成的序列為$[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]$

而我們思考$next\_permutatin$是怎麼判斷下一個排列的,假設某一個序列長度為$n$,最長的遞減的字尾長度$k$,那麼它的下一個排列是這樣產生的:選取序列第$n-k$個數,與後$k$個數中最小的那個交換(其實就是最後一個),然後將後$k$個數按從小到大排序。

 

如圖所示,若想要成為第二種情況,則$A$集合需等於$A’$集合。

而這時我們能確定$A$當前的一定不是遞減的,所以問題可以轉換成排除法當前序列末尾$k$個是按序遞減的情況數。

舉個例子:

$k=1$時,排除$[3,1,3],[2,2,1],[3,2,3],[1,3,1].[2,3,2]$

$k=2$時,排除$[(3,2),2],[(3,1),3]$

所以說我們現在只要求不行的方案數即可。

只要確定了前$k-x$個數,那麼後面關於$x$的遞減順序是一定的。

所以當k=x時,排除方案數為$A_n^k$,但是最後一個是沒有連線的,所以要-1,即為$A_n^k-1$

所以總方案數為$n\times n!-(n-1) - \sum_{k=1}^{n-1} (\frac{n!}{k!}-1)$.

整理的$n\times n!-\sum_{k=1}^{n-1} \frac{n!}{k!}$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define int long long
#define mod 998244353
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*f;
}
const int N=2000001;
int ans,n,fac[N],f[N];
signed main(){
    n=read();fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i,fac[i]%=mod;
    f[n]=1;
    for(int i=n-1;i>=1;i--) f[i]=f[i+1]*(i+1),f[i]%=mod;
    ans=n*fac[n];
    for(int i=1;i<n;i++) ans=((ans-f[i])%mod+mod)%mod;
    printf("%d\n",ans);
}
View Code