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)!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章