CF886E Maximum Element

来源:互联网 发布:毛星云windows 编辑:程序博客网 时间:2024/06/16 02:23

Maximum Element

题目描述
http://codeforces.com/contest/886/problem/E

题解

日常不会计数题。
重度推公式困难症患者。
定义状态f[i]表示i个数离散化成排列,最大的那个放最后面的合法方案数。
那么,枚举n的位置,ans=Σf[i]*A(n-1,n-i)。
考虑转移。对于f[i],考虑第二大的数字i-1。若i-1在i-k前则肯定满足。否则,如果要满足,则以i-1结尾的前缀串离散化后必须要满足条件,这样的方案数位f[j](j位i-1的位置)。
所以得到转移式:f[i]=(i-k-1)(n-2)!+Σf[j] A(n-2,n-j-1)。
这样的dp是O(n^2)的,不能AC。
把排列的式子拆开,把(n-2)!提出来,可以优化成(n-2)!*Σf[j]/(j-1)!。利用前缀和即可把复杂度降到O(n)。

代码

#include<bits/stdc++.h>#define ll long long#define mod 1000000007#define N 1000005using namespace std;int n,k;ll sum,ans,fac[N],inv[N],f[N];ll Pow(ll a,int b){  ll res=1;  while(b)  {    if(b&1)res=res*a%mod;    a=a*a%mod;b>>=1;  }  return res;}ll A(int n,int m){return fac[n]*inv[n-m]%mod;}int main(){  scanf("%d%d",&n,&k);fac[0]=1;  for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;  inv[n]=Pow(fac[n],mod-2);  for(int i=n;i;i--)inv[i-1]=inv[i]*i%mod;  for(int i=k+2;i<=n;i++)  {    sum=(sum+f[i-1]*inv[i-2]%mod)%mod;    sum=(sum-f[i-k-1]*inv[i-k-2]%mod+mod)%mod;    f[i]=((i-k-1)*fac[i-2]%mod+fac[i-2]*sum%mod)%mod;    ans=(ans+A(n-1,n-i)*f[i]%mod)%mod;  }  printf("%d\n",ans);  return 0;}
原创粉丝点击