Description
在OI界存在着一位传奇选手——QQ,他总是以风格迥异的搞笑代码受世人围观
某次某道题目的输入是一个排列,他使用了以下伪代码来生成数据
while 序列长度< n do
{
随机生成一个整数属亍[1,n]
如果这个数没有出现过则加入序列尾
}
聪明的同学一定发现了,这样生成数据是徆慢的,那么请你告诉QQ,生成一个n排列的期望随机次数
100%数据满足n≤2^31
Analysis
题目转化
解一个方程, 就能知道答案为
∑i=1nni
solution 1 打表
当然不是把每个答案都打出来,首先打的是
∑ni=11i
的表,这样才能一直算下去,但是空间会爆
然后有一个很劲的技巧,每隔10000000打一个数,那么各个答案之间只差一千万,可以直接算,而且空间又不会爆,很好的平衡了时空复杂度
solution 2 调和级数
这个答案显然是调和级数h(n)*n
性质
当 n 很大的时候,h(n)与ln(n)的差约等于欧拉常数,不过 n 较小的时候误差较大
所以当n较小的时候O(n)算,n较大时直接用(ln(n)+euler)*n就好了
PS:这个方法谁
TM
比赛时想得到啊
打表大法好!打表大法好!打表大法好!
Code
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef double db;
const db euler=0.57721566490153286060651209;
int main()
{
int n;
scanf("%d",&n);
if(n>=50000000) printf("%.lf",(log(n*1.0)+euler)*n);
else
{
db ans=0;
fo(i,1,n) ans+=n*1.0/i;
printf("%.lf",ans);
}
return 0;
}