codeforces 886E&&889C Maximum Element

E. Maximum Element
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

One day Petya was solving a very interesting problem. But although he used many optimization techniques, his solution still got Time limit exceeded verdict. Petya conducted a thorough analysis of his program and found out that his function for finding maximum element in an array of n positive integers was too slow. Desperate, Petya decided to use a somewhat unexpected optimization using parameter k, so now his function contains the following code:

int fast_max(int n, int a[]) { 
    int ans = 0;
    int offset = 0;
    for (int i = 0; i < n; ++i)
        if (ans < a[i]) {
            ans = a[i];
            offset = 0;
        } else {
            offset = offset + 1;
            if (offset == k)
                return ans;
        }
    return ans;
}

That way the function iteratively checks array elements, storing the intermediate maximum, and if after k consecutive iterations that maximum has not changed, it is returned as the answer.

Now Petya is interested in fault rate of his function. He asked you to find the number of permutations of integers from 1 to n such that the return value of his function on those permutations is not equal to n. Since this number could be very big, output the answer modulo 109 + 7.

Input

The only line contains two integers n and k (1 ≤ n, k ≤ 106), separated by a space — the length of the permutations and the parameter k.

Output

Output the answer to the problem modulo 109 + 7.

Examples
input
Copy
5 2
output
22
input
Copy
5 3
output
6
input
Copy
6 3
output
84
Note

Permutations from second example:

[4, 1, 2, 3, 5][4, 1, 3, 2, 5][4, 2, 1, 3, 5][4, 2, 3, 1, 5][4, 3, 1, 2, 5][4, 3, 2, 1, 5].

题意:问你求最大值的上述程序,对于所有排列错误的方案数有多少种。
题解:
显然题目让我们找到一个数字,这个数字比前面的数字都小,比后k个数字都大,并且它不是最大值。
我们用dp[i]表示前i的排列中满足这样的数字的个数,那么我们转移时要考虑两种情况:1.中间这个数字比i-1大,2.中间这个数字等于i-1。
如果是情况2,那么i就在最后,i-1位置就有i-k-1种数字可以选择,其他数字随意,所以情况数为(ik1)(i2)!
如果是情况1,那么一定是从i-j转移过来的,我们把前i-2个数字离散化之后对应一个排列,那么我们随意选择j-1个数字,
情况就是C(i-2,j-1),之后再乘上随意排列的方案数(i-j-1)!得到了dp方程:

这样的话用前缀和优化一下就可以了。
最后的答案统计和情况1是同理的,我们选择一些数放置后,其他的数字随意排列,公式为
代码:(超短)
#include <cstdio>  
#include <iostream>  
#include <cstring>   
using namespace std;  
typedef long long ll;         
ll inv[1000005],fac[1000005]={1},dp[1000005],sum[1000005],n,k,ans=0;  
ll pow(ll di,ll mi) 
{    
    ll sum=di,ans=1,i=mi;
    for(;i;i>>=1) 
	{    
        if(i&1) ans=(ans*sum)%1000000007;    
        sum=sum*sum%1000000007; 
    }  
    return ans;    
}  
int main() 
{  
    cin>>n>>k;  
    if(n<=k+1) return printf("0\n"),0;  
    for(int i=1;i<=n;i++) fac[i]=(fac[i-1]*i)%1000000007;  
    for(int i=1;i<=n;i++) inv[i]=pow(fac[i],1000000005);
    for(int i=k+2;i<=n;i++) 
	{  
        dp[i]=(((i-k-1)+(sum[i-1]-sum[i-k-1]+1000000007)%1000000007)*fac[i-2])%1000000007;  
        sum[i]=(sum[i-1]+(dp[i]*inv[i-1])%1000000007)%1000000007;  
        ans=(ans+(((dp[i]*fac[n-1])%1000000007)*inv[i-1])%1000000007)%1000000007;  
    }  
    cout<<ans;  
}  


(ik1)(i2)!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章