HDU7297 杭电多校(二) 1011-SPY finding NPY

题面
题意: 主人公在一堆人里选人,他们的能力值分别为 1 − n 1-n 1n,主人公采取如下策略:取一个 k k k,这 k k k个人全不要,设这 k k k个人中能力值最大的为 m m m,从 k + 1 k+1 k+1开始选出第一个比 m m m大的。要让选出的人是能力值最高的概率最大,求 m m m

考试时做到这题已经没时间耐心推导规律了,就打了几个表去 o e i s oeis oeis上找规律,发现了一个神奇规律 ⌊ n n + 1 ( n + 1 ) n ⌋ \lfloor\frac{n^{n+1}}{(n+1)^n}\rfloor (n+1)nnn+1,正好可以过样例,调调改改直接交了,结果 W A WA WA了,后来对拍发现差了好多。

其实公式并不难推,我们设 f ( n , k ) f(n,k) f(n,k)为取到能力值最高的概率,则有
f ( n , 0 ) = 1 n , f(n,0)=\frac{1}{n}, f(n,0)=n1,
f ( n , k ) = ∑ i = k + 1 n 1 n k i − 1 = k n ∑ i = k n − 1 1 i f(n,k)=\sum_{i=k+1}^{n}\frac{1}{n}\frac{k}{i-1}=\frac{k}{n}\sum_{i=k}^{n-1}\frac{1}{i} f(n,k)=i=k+1nn1i1k=nki=kn1i1
因此求出 1 i \frac{1}{i} i1的前缀和,遍历枚举 k k k即可。时间复杂度 O ( T n ) O(Tn) O(Tn)

如果再对这个函数进行求导,可以发现这个函数是先增后减的,最大值为 n e \frac{n}{e} en,因此求出 n e \frac{n}{e} en,并枚举左右两侧的数也可以 O ( T ) O(T) O(T)求出结果。

#include
#define N 10010
using namespace std;
double sum[N],ans;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
int n,T;
int main ()
{
    for(int i=1;i<=10000;i++)sum[i]=sum[i-1]+1.0/i;
    read(T);
    while(T--){
        read(n);double ans=1.0/n;int ak=0;
        for(int k=1;k<=n;k++){
            if(k*1.0/n*(sum[n-1]-sum[k-1])>ans)ans=k*1.0/n*(sum[n-1]-sum[k-1]),ak=k;
        }
        cout<<ak<<endl;
    }

}

你可能感兴趣的:(集训,考试,数论,c++,数论)