#1751 : 随机排列2
描述
一个长度为n的排列p[1..n]的价值是这样定义的:一开始你有一个数x,x的值一开始为0,然后对于1 ≤ i ≤ n,如果p[i] > x,则令x=p[i];排列p[1..n]的价值就是x的值的改变次数。
求对于所有长度为n的[1,2…n]的排列,他们的价值之和,答案对109+7取模。
输入
第一行一个正整数n. (1 ≤ n ≤ 106)。
输出
输出一个非负整数,表示答案。
样例解释
对于排列[1,2,3],x的值会依次变成1,2,3,所以价值为3.
对于排列[1,3,2],x的值会依次变成1,3,所以价值为2.
对于排列[2,1,3],x的值会依次变成2,3,所以价值为2.
对于排列[2,3,1],x的值会依次变成2,3,所以价值为2.
对于排列[3,1,2],x的值会依次变成3,所以价值为1.
对于排列[3,2,1],x的值会依次变成3,所以价值为1.
所以所有长度为 3 的排列的价值之和为11.
3样例输出
11
题解:
这题官方题解格式太牛逼(不是人看的),网上的那个题解是找规律的根本没有证明。。。
我无奈之下问了我校本届去北大的毕业生hzq大牛,结果他直接秒了orz%%%。。
大佬原话:
我们从大到小放数字,第一个放n,第二个放n-1......
固定n,此时n对答案产生的贡献必定为1(因为没有比它大的)
然后放n-1,此时n-1可以n的前面或后面,放在前面产生为1的贡献,放在后面没有贡献,所以此时的期望贡献的(0+1)/2=1/2
然后放n-2。此时n,n-1已被放好,比如 n-1(n),n(n-1)。此时n-2可能放在两个数之前,两个数之间或两个数后面,我们发现,只有放在最前面才可能有贡献,所以此时的期望贡献为1/3
后面以此类推,所以期望答案为1+1/2+1/3+......+1/n,最后再乘一个总方案数n!就是答案了。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long p=1e9+7;
void gcd(ll n,ll m,ll &x,ll &y){
if(!m){
x=1;y=0;
return;
}
gcd(m,n%m,x,y);
ll t=x;
x=y;y=t-n/m*y;
}
long long ex_gcd(ll now){
ll x,y;
gcd(now,p,x,y);
x=(x%p+p)%p;
return x;
}
int main(){
ll i,n,ans=0,sum;
scanf("%lld",&n);
sum=1;
for(i=1;i<=n;i++)sum=(sum*i)%p;
for(i=1;i<=n;i++)ans=(ans+(sum*ex_gcd(i))%p)%p;
printf("%lld",ans);
}