2017 Multi-University Training Contest

来源:互联网 发布:网络市场监管 编辑:程序博客网 时间:2024/06/05 07:47

题目大意:

给你一个序列An,然后求有多少个序列Bn

满足Bi<=Ai,且这个序列的gcd不为1

 

题解:

考虑这样做

枚举一个因子k,然后求出有多少个序列的gcd包含这个因子k

然后把结果容斥一下,我们会发现,这个容斥恰好就是求莫比乌斯函数

所以直接先预处理出来即可

于是k从2到n依次枚举,然后把结果乘以u(k)加到最后的答案里。

 

另一个问题是,如何快速求出有多少个序列呢,如果单纯的把每个数除以k然后加起来,就是n^2logn

显然会超时。

所以这里先把数存起来,然后整体来做

对于k来说,每次就枚举k,2k,3k.....m*k,然后可以得到,能包含k的数有多少个,2k的数有多少个,那么我们就可以在n/k的复杂度下统计出来有多少个序列

然后枚举k,最后就是n+n/2+...n/k = nlogn的复杂度了

(可能有更好的做法)

 

复制代码
#include <iostream>#include <cstring>#include <vector>#include <cstdio>using namespace std;const int maxn = 1e5 + 100;const int MOD = 1000000007;typedef long long LL;LL minpri[maxn], H[maxn], a[maxn], ans[maxn], flag[maxn];vector<int> prime;const int maxlen=maxn;int mu[maxlen],prinum[maxlen], len=0;void CalPri(){    int num[maxlen];    for(int i=2;i<maxlen;i++)num[i]=i;    for(int i=2;i<maxlen;i++){        if(num[i]==0)continue;        prinum[len++]=i;        mu[i]=-1;        for(int j=2*i;j<maxlen;j+=i)            num[j]=0;    }}void Calmu(){    CalPri();    mu[1]=1;    for(int i=2;2*i<=maxlen;i++){        for(int j=0;j<len&&prinum[j]*i<maxlen;j++){            if(i%prinum[j]==0){                mu[prinum[j]*i]=0;                break;            }            mu[prinum[j]*i]=-mu[i];        }    }}LL mypow(LL a, LL b){    LL ANS = 1;    for(; b; b >>= 1){ if(b&1) (ANS *= a) %= MOD; (a *= a) %= MOD; } return ANS;}int main(){    int T, n;    cin>>T;    Calmu();    for(int ncase = 1; ncase <= T; ncase++){        scanf("%d", &n);        memset(H, 0, sizeof(H));        memset(ans, 0, sizeof(ans));        LL ANS = 0, Max = 0, Min = 1e9;        for(int i = 1; i <= n; i++) scanf("%d", &a[i]), H[a[i]]++, Max = max(Max, a[i]), Min = min(Min, a[i]);        for(int i = Max; i >= 0; i--) H[i] += H[i+1];        //for(int i = 1; i <= Max; i++) cout<<H[i]<<" "; cout<<endl;        for(int x = 2; x <= Min; x++){            if(mu[x] == 0) continue;            int tot = 0, lans = n;            for(int i = 1; i*x <= Max; i++){                ans[tot] = lans - H[i*x];                lans = H[i*x];                tot++;            }            ans[tot] = lans;            //for(int i = 1; i <= tot; i++) cout<<ans[i]<<" "; cout<<endl;            LL temp = tot > 0 ? 1 : 0;            for(int i = 2; i <= tot; i++) (temp *= mypow(i, ans[i])) %= MOD;            (ANS += temp*(-mu[x])) %= MOD;            for(int i = 1; i <= tot; i++) ans[i] = 0;        }        (ANS += MOD) %= MOD;        cout<<"Case #"<<ncase<<": "<<ANS<<endl;    }    return 0;}
原创粉丝点击