CodeForces

来源:互联网 发布:高速公路收费查询软件 编辑:程序博客网 时间:2024/05/22 13:06

题目大意:

首先定义f(n):有n个人参加比赛,可以进行任意轮的比赛,每一轮是将他们分成任意组(必须保证每组人数相同),然后每组的所有人两两之间都必须进行一次比较。f(n)就表示确定第一名所需的最少比较次数。

现在给你:l,r,t,让你求:

 i=l r t il f(i) 

分析:

首先说明f(x)的求法:

f(x)=⎧ ⎩ ⎨ ⎪ ⎪ ⎪ ⎪ xk (k)(k1)2 +f(xk )(k)(k1)2  xx kx1 

这也就是等价于,如果一个数x可以质因数分解成:q 1 q 2 q 3 ...q n  。那么最优的比赛方法就是,先每一组是q 1  人,下一轮每一组是q 2  人,以此方法直到最后找到胜者。

下面证明该贪心策略的正确性:

首先,证明“假如一个数x 可以表示成两个整数q 1 ,q 2  的乘积,那么每组x 人一定不如首先每组q 1  人,下一轮每组q 2  ”:

如果每组x人,那么比赛次数为:f 1 (x)=(x1)x2 =(q 1 q 2 1)q 1 q 2 2  
如果先q 1  q 2  人,那么比赛次数为:f 2 (x)=f 2 (q 1 q 2 )=q 2 ((q 1 1)q 1 2 )+(q 2 1)q 2 2  
那么:f 1 (x)f 2 (x)=q 2 (q 2 1)(q 2 1 1)2 0 

这就说明分成两次比赛次数更少。证毕~

其次,证明“假如q 1 >q 2  ,那么先分成q 2  组,再分成$$q_1组比赛,总比赛次数更少”:

如果先q 1  q 2  那么比赛次数a为:a=q 2 (q 1 1)q 1 2 +(q 2 1)q 2 2  
如果先q 2  q 1  那么比赛次数a为:a=q 1 (q 2 1)q 2 2 +(q 1 1)q 1 2  
则:ab=(q 1 1)(q 2 1)(q 1 q 2 )2 >0 

这就说明对于每一轮尽量使每组人数更小才能使得总比赛次数最少。证毕~

综合以上连个结论,我们就得到了贪心策略。

然后就是如何更快的求出一段连续的f(x)的值:

这里有点 类似于线性筛素数的方法,每次枚举当前最小的素数的整数倍,同时对f(x) 的值进行对应的类加操作,程序中我用了一个 f_full [ i ] 数组表示当前 i 还剩多少未被除净。

代码:

#include<bits/stdc++.h>#define maxn 5000500#define mod 1000000007using namespace std;long long int t;int l,r;long long int t_pow[maxn],f[maxn],f_full[maxn];int is_prime[maxn];//bool appear[maxn];void init(){    for(int i=0;i<maxn;i++)    {        f[i]=0;f_full[i]=(long long int)i;        is_prime[i]=1;    }}void init_t(){    t_pow[0]=1;    for(int i=1;i<=r-l;i++)    {        t_pow[i]=t_pow[i-1]*t;        t_pow[i]%=mod;        //cout<<t_pow[i]<<endl;    }}/*void test(){    //memset(appear,0,sizeof(appear));    int num=0;    for(int i=1;i<=r;i++)    {        int flag=0;        for(int j=2;j<sqrt(i)+1;j++)        {            if(i%j==0)            {                flag=1;break;            }        }        if(flag==0)        {            num++;            //appear[i]=1;            //cout<<i<<" ";        }    }    cout<<"num="<<num<<endl;}*/void init_f(){    for(int i=2;i<=r;i++)    {        if(is_prime[i]==1)//i是质数        {            int k=2;            f[i]=(long long int)i*(long long int)(i-1)/2;            f[i]%=mod;            f_full[i]=1;            while(i*k<=r)            {                int temp=i*k;k++;                is_prime[temp]=0;//筛素数                while(f_full[temp]%(long long int )i==0)                {                    f_full[temp]/=(long long int)i;                    f[temp]+=(((f_full[temp])*(((long long int)i*(long long int)(i-1)/2)%mod))%mod);                    f[temp]%=mod;                }            }        }    }}int main(){    scanf("%lld%d%d",&t,&l,&r);    //test();    init();    init_t();    init_f();    long long int ans=0;    for(int i=0;i<=r-l;i++)    {        //printf("t[%d]=%lld   f[%d]=%lld   f_full[%d]=%lld\n",i,t_pow[i],l+i,f[l+i],i+l,f_full[i+l]);        ans=ans+t_pow[i]*f[l+i];        ans%=mod;    }    printf("%I64d\n",ans);}
原创粉丝点击