题解 CF886E Maximum Element

看不懂题解里那些柿子是怎么推出来的。讲一下我自己不同于题解的思考方式,但是两者殊途同归,代码部分大体一致。

考虑 f_ifi 表示长度为 ii 的以 ii 为最大值的每个位置后面不出现连续 kk 个小于它的排列数量,注意,这时候我们仅仅考虑前面这些数的相对关系。

接下来考虑从 f_ifi 转移到 f_jfj,这时候我们强制转移的时候 i+1\sim j-1i+1j1 的数均小于 ii 和 jj 位置上最终填的数。

首先显然 j-i-1<kji1<k 时才能转移。

中间的数在计算的时候考虑将这个数插进去能插在哪个位置,假设前面有 kk 个数,根据条件这个数要小于最大值,所以答案 \times k×k,然后 k++k++。

而第 jj 个数前面没有一个数可能大于他了,所以他只有唯一的一种选择是成为最大值。

所以我们最终发现这个转移系数是一个差为 11 的递增数列的乘积,把它拆成 \frac{fac_j}{fac_i}facifacj 的形式之后就可以前缀和优化转移了。

算完这个了,我们可以枚举最终 nn 在位置 ii ,那么 \text{ans}=nans=n 的排列要满足前面每个位置后面不出现连续 kk 个小于它,并且发现剩下的数也能够考虑插进去的方案数。所以类似的,f_ifi 对答案的贡献的系数也是一个差为 11 的递增数列的乘积。

时间复杂度 O(n)O(n)。

//The Hunting Party - Keys To The Kingdom
//好想做嘉然小姐的狗啊~
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define ll long long
#define mp make_pair
#define pa pair < int,int >
#define fi first
#define se second
#define inf 1e18
#define mod 1000000007
#define int ll
#define N 2000005
using namespace std;
inline char gc(){static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
#define gc getchar
inline ll read(){char c=gc();ll su=0,f=1;for (;c<'0'||c>'9';c=gc()) if (c=='-') f=-1;for (;c>='0'&&c<='9';c=gc()) su=su*10+c-'0';return su*f;}
inline void write(ll x){if (x<0){putchar('-');write(-x);return;}if (x>=10) write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x),putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}
int n,m,fac[N],inv[N];
int f[N];
int s[N];
int ans;
int quickPower(int x,int y)
{
    int res=1;
    while (y)
    {
        if (y&1) res=res*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return res;
}
void What_will_Diana_eat_today()
{
    n=read(),m=read();
    fac[0]=1;
    for (int i=1;i<=n;i++)
    {
        fac[i]=fac[i-1]*i%mod;
    }
    inv[n]=quickPower(fac[n],mod-2);
    for (int i=n;i>=1;i--) inv[i-1]=inv[i]*i%mod;
    f[1]=1;
    for (int i=1;i<n;i++)
    {
        s[i]=(s[i-1]+f[i]*inv[i-1]%mod)%mod;
        int x=i-m;
        if (x<0) x=0;
        f[i+1]=f[i+1]+fac[i-1]*(s[i]-s[x]+mod)%mod;
        f[i+1]=(f[i+1])%mod;
    }
    for (int i=1;i<=n;i++) ans=(ans+f[i]*(fac[n-1]*inv[i-1]%mod)%mod)%mod;
    writeln((fac[n]-ans+mod)%mod);

}
signed main()
{
    int T=1;
    while (T--)
    {
          What_will_Diana_eat_today();
    }
}