hihocoder#1751 : 随机排列2

11 篇文章 0 订阅
7 篇文章 0 订阅

#1751 : 随机排列2

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

一个长度为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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值