Hdu 5321 2015多校对抗赛三

Beautiful Set

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 205    Accepted Submission(s): 81


Problem Description
I’ve read many problems in my ICPC career, sometimes the meaning of a problem often makes me confused.
When I read a problem more than three times and still can’t get the idea what is the problem saying about, I may become like this

or


I hope you won’t be the above person after you read this problem.
Mr. Zstu and Mr. Hdu get a set of numbers { A1,A2,...,An }, they have different opinions about the beautiful value of the set.
Mr. Zstu defines the beautiful value like this:
Make the set become a sequence, the beautiful value of the sequence is the sum of all the interval’s gcd(greatest common divisor), and the beautiful value of the set is the sum of the beautiful value of all the possible sequence. For example, set{ 1,2,3 } can be six different sequence { 1,2,3 },{ 1,3,2 },{ 2,1,3 },{ 2,3,1 },{ 3,1,2 },{ 3,2,1 }.


Mr. Hdu defines the beautiful value like this:
For k from 1 to n, choose k numbers of the set, and calculate the gcd of the k numbers. The beautiful value of the k numbers is k * (gcd of the k chosen numbers). The beautiful value of the set is the sum of all of the beautiful value of k numbers.
Which beautiful value is larger, Mr. Zstu and Mr. Hdu invite the judge Mr. Xiasha to help.
Given that both of the value are too big, the stupid Mr. Xiasha mod both of the values by 258280327, so here is the question, which value is bigger after mod operation?

 

Input
There are multiple test cases.
Each test case begins with an integer n (1n100000)
The next line is n integers  A1,A2,...,An
All of the integers are between 1 and 100000.
 

Output
For each test case, if the beautiful value is equal between Mr. Zstu and Mr. Hdu, output “Equal”, followed the beautiful value , otherwise output the person’s name with bigger beautiful value and followed the beautiful value.
 

Sample Input
  
  
2 2 3 1 233
 

Sample Output
  
  
Mr. Zstu 12 Equal 233
 

Author
ZSTU
 

题意:

有两种对集合求值得方式,问哪一种求得的值大。

第一种:集合所有的排列数为n,某一种排列数的值为所有区间的gcd的和。那么集合的值为所有排列的值得和。

第二种:在集合中任选k个数,k乘以这k个数的gcd为这个选择的值。所有的选择的和为集合的值。

莫比乌斯题:

莫比乌斯定义:mu[1]  = 1   mu[x]=(-1)^k   x=p1*p2*....*pk    若某个质因子次幂≥2,mu[x]=0

F[n]=sigma( f[d] )  d|n   莫比乌斯约束形式 反演:f[n] = sigma( mu[d]*F[n/d]  ) d|n   

F[n]=sigma( f[d] )  n|d  莫比乌斯倍数形式 反演:f[n] = sigma( mu[d/n]*F[d]  ) n|d

F[n]意义为倍数n的数的个数 f[n]表示数n的个数

此题采用倍数形式:

对于第一种计算方式:

如果我们能求得gcd=k的个数,那么答案就等于1*f[1]+2*f[2]+3*f[3]+.......最大计算到10w,即给的数据范围

我们可以很容易的得到F[i]的值,利用莫比乌斯可以很快求得f[i]的值

F[i]=sigma( C(cnt[i]-1,j-1)*(j-1)!*(n-i+1)! )   次意义是:cnt[i]表示i的倍数的个数,F[i]表示gcd为i的倍数的个数。

那么,我选择一个数i的倍数。还剩cnt[i]-1个数i 的倍数,我可以从剩下的数里面任意选择和已选择的组合,有C(cnt[i]-1,j-1])种情况,j-1表示选的个数。

这样写,j的范围自然就是[1,cnt[i]]了。这不是重点。那么这选择的j-1个数就有(j-1)!种排列,和已选则的那个绑定在一起,和剩下的所有n-i个数一起排列,

有(n-i+1)种排列。如此就可以得到F[i]了。

对于10w,他的因子最多就2*sqrt(10w)个。所以复杂度为 nsqrt(n) 。

第二种计算方式:

同理:F[i]=cnt[i]*2^(cnt[i]-1)

意思是:我先选择一个i的倍数的数,这是必须要有一个。那么剩下cnt[i]-1个数,我选或则不选,总共有2^(cnt[i]-1)种选择。


莫比乌斯反演后,这题就有结果了。

需要用到的预处理很多:莫比乌斯系数,阶乘,组合数(用逆元),素数。

统计cnt[i]用sqrt的筛法。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1000000
#define MOD 258280327
#define LL long long
int notprime[maxn+10];
int prime[maxn+10],tot;
int mu[maxn+10]={0,1};
LL jie[maxn+10];
LL inv[maxn+10];
LL power(LL x,LL k){
    LL res=1,t=x;
    while(k){
        if(k&1)res=res*t%MOD;
        t=t*t%MOD;
        k>>=1;
    }
    return res%MOD;
}
void init(){
    jie[0]=jie[1]=1;
    tot=0;
    mu[1]=1;
    inv[0]=inv[1]=1;
    for(int i=2;i<=maxn;i++){
        jie[i]=i*jie[i-1]%MOD;
        inv[i]=power(jie[i],MOD-2);
        if(!notprime[i]){
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot&&i*prime[j]<=maxn;j++){
            notprime[i*prime[j]]=1;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
}
int n;
int ma;
int cnt[maxn+10];
LL F1[maxn+10],F2[maxn+10];
LL ans1,ans2;
void calc(){
    for(int i=1;i<=ma;i++){
        LL tmp=0;
        for(int j=1;j<=cnt[i];j++){
            LL a=jie[cnt[i]];
//            LL b=power(jie[cnt[i]-j],MOD-2);
            LL b=inv[cnt[i]-j];
            tmp=(tmp+a*b%MOD*jie[n-j+1]%MOD)%MOD;
        }
        F1[i]=tmp;
        if(cnt[i]>0)
            F2[i]=cnt[i]*power(2,cnt[i]-1);
        else F2[i]=0;
    }
    LL tmp1,tmp2;
    ans1=ans2=0;
    for(int i=1;i<=ma;i++){
        tmp1=tmp2=0;
        for(int j=i;j<=ma;j+=i){
            tmp1=(tmp1+mu[j/i]*F1[j]%MOD)%MOD;
            tmp2=(tmp2+mu[j/i]*F2[j]%MOD)%MOD;
        }
        ans1=(ans1+i*tmp1%MOD)%MOD;
        ans2=(ans2+i*tmp2%MOD)%MOD;
    }
}
int main(){
    init();
    while(~scanf("%d",&n)){
        for(int i=1;i<=maxn;i++)cnt[i]=0;
        ma=0;
        for(int i=0;i<n;i++){
            int x;scanf("%d",&x);
            if(ma<x)ma=x;
            for(int j=1;j*j<=x;j++){
                if(j*j==x)cnt[j]++;
                else if(x%j==0){
                    cnt[j]++;
                    cnt[x/j]++;
                }
            }
        }
        calc();
        if(ans1==ans2)printf("Equal %lld\n",ans1);
        else if(ans1>ans2)printf("Mr. Zstu %lld\n",ans1);
        else printf("Mr. Hdu %lld\n",ans2);
    }
    return 0;
}

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1000000
#define MOD 258280327
#define LL long long
int notprime[maxn+10];
int prime[maxn+10],tot;
int mu[maxn+10]={0,1};
LL jie[maxn+10];
LL inv[maxn+10];
LL power(LL x,LL k){
    LL res=1,t=x;
    while(k){
        if(k&1)res=res*t%MOD;
        t=t*t%MOD;
        k>>=1;
    }
    return res%MOD;
}
void init(){
    jie[0]=jie[1]=1;
    tot=0;
    mu[1]=1;
    inv[0]=inv[1]=1;
    for(int i=0;i<=maxn;i++)notprime[i]=0;
    for(int i=2;i<=maxn;i++){
        jie[i]=i*jie[i-1]%MOD;
        inv[i]=power(jie[i],MOD-2);
        if(!notprime[i]){
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot&&i*prime[j]<=maxn;j++){
            notprime[i*prime[j]]=1;
            if(i%prime[j]==0){
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
}
int n;
int ma;
int cnt[maxn+10];
LL F1[maxn+10],F2[maxn+10];
LL calc_1(){
    for(int i=1;i<=ma;i++){
        LL tmp=0;
        for(int j=1;j<=cnt[i];j++){
            LL a=jie[cnt[i]];
//            LL b=power(jie[cnt[i]-j],MOD-2);
            LL b=inv[cnt[i]-j];
            tmp=(tmp+a*b%MOD*jie[n-j+1]%MOD)%MOD;
        }
        F1[i]=tmp;
    }
    LL res=0;
    for(int i=1;i<=ma;i++){
        LL tmp=0;
        for(int j=i;j<=ma;j+=i){
            tmp=(tmp+mu[j/i]*F1[j]%MOD)%MOD;
        }
        res=(res+i*tmp%MOD)%MOD;
    }
    return res;
}
LL calc_2(){
    for(int i=1;i<=ma;i++){
        if(cnt[i]>0)
            F2[i]=cnt[i]*power(2,cnt[i]-1);
        else F2[i]=0;
    }
    LL res=0;
    for(int i=1;i<=ma;i++){
        LL tmp=0;
        for(int j=i;j<=ma;j+=i){
            tmp=(tmp+mu[j/i]*F2[j]%MOD)%MOD;
        }
        res=(res+tmp*i)%MOD;
    }
    return res;
}
int main(){
    init();
    while(~scanf("%d",&n)){
        for(int i=1;i<=maxn;i++)cnt[i]=0;
        ma=0;
        for(int i=0;i<n;i++){
            int x;scanf("%d",&x);
            if(ma<x)ma=x;
            for(int j=1;j*j<=x;j++){
                if(j*j==x)cnt[j]++;
                else if(x%j==0){
                    cnt[j]++;
                    cnt[x/j]++;
                }
            }
        }
        LL ans1 = calc_1();
        LL ans2 = calc_2();
        if(ans1==ans2)printf("Equal %lld\n",ans1);
        else if(ans1>ans2)printf("Mr. Zstu %lld\n",ans1);
        else printf("Mr. Hdu %lld\n",ans2);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值