• 【CF886E】Maximum Element DP


    【CF886E】Maximum Element

    题意:小P有一个1-n的序列,他想找到整个序列中最大值的出现位置,但是他觉得O(n)扫一遍太慢了,所以它采用了如下方法:

    1.逐个遍历每个元素,如果这个元素比当前记录的最大值大,则令最大值等于当前元素,并令cnt=0
    2.如果这个元素没有当前元素大,则cnt++。
    3.如果cnt=k,则返回当前最大值

    现在小P想知道有多少种序列在使用他的方法时会得到错误的答案。为了简化问题,我们假定原序列是一个1-n的排列。即我们要求的是:给定n和k,有多少个1-n的排列,在使用上述算法时,会得到错误的答案。

    n,k<=10^6

    题解:好难的DP题。

    令f[n]表示1-n的排列中,$a_n=n$且能得到错误答案的方案数。显然当n<=K时f[n]都是0。

    考虑枚举n-1的出现位置,如果n-1的出现位置在[1,n-k-1]中,那么这样的排列一定是错误的。这样的方案数是(n-2)!*(n-k-1)。

    如果n-1在[n-k,n-1]中,那么如果答案是错误的,最大值只能是前n-2个数中的一个。设n-1的位置是j,那么我们将n-1和它前面的数看成一个新的序列,那么这个序列错误的方案数就是f[j]。又由于前面的j个数其实可以在n-2里随便取,所以方案数其实是$f[j]frac {(n-2)!} {(j-1)!}$。

    所以DP方程:$​f[n]=(n-2)!(n-k-1)+sumlimits_{j=n-k}^{n-1}f[j]frac{(n-2)!}{(j-1)!}$

    用前缀和维护$frac{f[j]}{(j-1)!}$即可。

    答案是什么呢?仿照上面的推导过程可以知道$ans=sumlimits_{i=k+1}^nf[i]frac{(n-1)!}{(i-1)!}$。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const int maxn=1000010;
    const ll P=1000000007;
    int n,m;
    ll jc[maxn],ine[maxn],jcc[maxn],f[maxn],s[maxn];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int i;
    	ine[0]=ine[1]=jc[0]=jc[1]=jcc[0]=jcc[1]=1;
    	for(i=2;i<=n;i++)	jc[i]=jc[i-1]*i%P,ine[i]=P-(P/i)*ine[P%i]%P,jcc[i]=jcc[i-1]*ine[i]%P;
    	for(i=m+2;i<=n;i++)	f[i]=(i-m-1+s[i-1]-s[i-m-1]+P)*jc[i-2]%P,s[i]=(s[i-1]+f[i]*jcc[i-1])%P;
    	printf("%I64d",s[n]*jc[n-1]%P);
    	return 0;
    }
  • 相关阅读:
    【Netty学习】 ChannelInitializer 学习
    【Netty学习】Netty 4.0.x版本和Flex 4.6配合
    Spring框架学习
    【JS教程23】jquery链式调用
    【JS教程22】jquery特殊效果
    【JS教程21】数组及操作方法
    【JS教程20】jquery动画
    【JS教程19】jquery绑定click事件
    【JS教程18】jquery样式操作
    【JS教程17】jquery选择器
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8065213.html
Copyright © 2020-2023  润新知