题意:
如果一个排列中,对于任意的i∈[k+1,n]i\in[k+1,n]i∈[k+1,n],都有a[i]>min(a[i−k],...,a[i−1])a[i]>min(a[i-k],...,a[i-1])a[i]>min(a[i−k],...,a[i−1])成立,那么这个排列就是一个好的排列。nnn的排列中有多少个排列是好的排列?
Solution:
要这样的排列存在,首先必须让111出现在区间[1,k][1,k][1,k]内,设dp[i]dp[i]dp[i]为用iii个不相同的数计算出的这样的排列有多少个,不妨枚举111出现的位置jjj,那么[1,j−1][1,j-1][1,j−1]位置任意放置任何数,[j+1,i][j+1,i][j+1,i]用另外的i−ji-ji−j个数重新构成一个这样的排列,于是
dp[i]=∑j=1kAi−1j−1dp[i−j]
dp[i]=\sum_{j=1}^{k}A_{i-1}^{j-1}dp[i-j]
dp[i]=j=1∑kAi−1j−1dp[i−j]
这样的单次转移是O(k)O(k)O(k)的,但可以写成这样
dp[i]=(i−1)!∑j=1kdp[i−j](i−j)!
dp[i]=(i-1)!\sum_{j=1}^{k}\frac{dp[i-j]}{(i-j)!}
dp[i]=(i−1)!j=1∑k(i−j)!dp[i−j]
显然求和是区间和形式,维护dp[i]i!\frac{dp[i]}{i!}i!dp[i]的前缀和就可以O(1)O(1)O(1)转移
全排列问题似乎不需要太注意全排列?用ttt组每组元素都互异的数来等价替换全排列
// #include<bits/stdc++.h>
#include<iostream>
#include<ctime>
#include<queue>
#include<complex>
#include<cstdio>
#include<bitset>
#include<stack>
#include<cmath>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
using ll=long long;
const int N=1e7+5,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=998244353;
ll dp[N],fac[N],invfac[N],sum[N];
int n,k;
ll qpow(ll a,ll b)
{
ll ret=1,base=a;
while(b)
{
if(b&1) ret=ret*base%mod;
base=base*base%mod;
b>>=1;
}
return ret;
}
void initial()
{
for(int i=fac[0]=invfac[0]=1;i<N;i++) fac[i]=fac[i-1]*i%mod;
invfac[N-1]=qpow(fac[N-1],mod-2);
for(int i=N-2;i>=1;i--) invfac[i]=invfac[i+1]*(i+1)%mod;
}
int main()
{
initial();
cin>>n>>k;
//有多少个n的排列,使得a[i]>min(a[i-k],a[i-k+1],...,a[i-1]);
for(int i=1;i<=k;i++)
{
dp[i]=fac[i];
sum[i]=(sum[i-1]+dp[i]*invfac[i]%mod)%mod;
}
for(int i=k+1;i<=n;i++)
{
dp[i]=fac[i-1]*(((sum[i-1]-sum[i-k-1])%mod+mod)%mod)%mod;
sum[i]=(sum[i-1]+dp[i]*invfac[i]%mod)%mod;
}
cout<<dp[n];
return 0;
}
619



被折叠的 条评论
为什么被折叠?



