zoukankan      html  css  js  c++  java
  • P4619 [SDOI2018]旧试题 题解

    CSDN同步

    原题链接

    简要题意:

    [sum_{i=1}^A sum_{j=1}^B sum_{k=1}^C d(ijk) ]

    其中 (d(x)) 表示 (x) 的因数个数。

    一言不合就推式子!

    [sum_{i=1}^A sum_{j=1}^B sum_{k=1}^C d(ijk) ]

    [= sum_{i=1}^A sum_{j=1}^B sum_{k=1}^C sum_{x=1}^i sum_{y=1}^j sum_{z=1}^k [gcd(i,j)==1] [gcd(i,k)==1] [gcd(j,k)==1] ]

    [= sum_{x=1}^A sum_{y=1}^B sum_{z=1}^C [gcd(x,y)==1] [gcd(x,z)==1] [gcd(y,z)==1] lfloor frac{A}{x} floor lfloor frac{B}{y} floor lfloor frac{C}{z} floor ]

    [= sum_{i=1}^A sum_{j=1}^B sum_{k=1}^C [gcd(i,j)==1] [gcd(i,k)==1] [gcd(j,k)==1] lfloor frac{A}{i} floor lfloor frac{B}{j} floor lfloor frac{C}{k} floor ]

    [= sum_{i=1}^A sum_{j=1}^B sum_{k=1}^C lfloor frac{A}{i} floor lfloor frac{B}{j} floor lfloor frac{C}{k} floor sum_{u| gcd(i,j)} mu_u sum_{v| gcd(i,k)} mu_v sum_{w|gcd(j,k)} mu_k ]

    [= sum_{u=1}^{min(A,B)} mu_u sum_{v=1}^{min(A,C)} mu_v sum_{w=1}^{min(B,C)} mu_w sum_{gcd(u,v)|i}^A lfloor frac{A}{i} floor sum_{gcd(u,w)|j}^B lfloor frac{B}{j} floor sum_{gcd(v,w)|k}^C lfloor frac{C}{k} floor ]

    算法一

    我会暴力!

    时间复杂度:(O(n^3)). 实际得分:(0pt).

    恭喜你,一长串式子白推了

    算法二

    推式子基本结束了,你会发现,式子长得可怕,这并不是我们 (A) 题的前兆!比方说 二元弱化版 本人也写了 题解,可是弱化版推的最后式子很简单啊!

    所以首先我们分析,如果就这个式子枚举,(O(n^3)) 是跑不掉的。因为我们没有消掉一个 (sum),反而按照 所谓的莫比乌斯反演套路 增加了 (sum).

    [f_{y,x} = sum_{x|i}^y lfloor frac{y}{i} floor ]

    将原式后面的一长串简化:

    [sum_{u=1}^{min(A,B)} mu_u sum_{v=1}^{min(A,C)} mu_v sum_{w=1}^{min(B,C)} mu_w sum_{gcd(u,v)|i}^A lfloor frac{A}{i} floor sum_{gcd(u,w)|j}^B lfloor frac{B}{j} floor sum_{gcd(v,w)|k}^C lfloor frac{C}{k} floor ]

    [= sum_{u=1}^{min(A,B)} mu_u sum_{v=1}^{min(A,C)} mu_v sum_{w=1}^{min(B,C)} mu_w f_A(gcd(u,v)) f_B(gcd(u,w)) f_C(gcd(v,w)) ]

    这只是看起来简单了,实质上,(O(n log n)) 预处理 (f) 可以办到,但是就当前式子,大力枚举还是 (O(n^3)),没有一点部分分可拿。这是令人痛苦的地方。

    时间复杂度:(O(n^3)). 实际得分:(0pt).

    算法三

    越接近答案的推导,就显得越困难。现在我们到了黎明前那个最黑暗的时刻。

    我们考虑,什么时候 (u,v,w) 对答案没有贡献

    显然,(mu_u = 0)(mu_v=0)(mu_w=0) 都会没有贡献。

    (f_y(x) = 0),就需要 (gcd(u,v)>A)(gcd(u,w)>B)(gcd(v,w)>C).

    似乎情况还蛮多的?

    所以我们考虑感性一点,枚举 (gcd=g),然后 (u=ig , v=jg) 合法 当且仅当 (gcd(i,j)=1 , mu_u imes mu_v ot = 0 , operatorname{lcm}{u,v}=ijg leq max(a,b,c)).

    对于合法的 (u,v) 连边,我们就得到了一张图。

    那么合法的情况是怎样的?即 (u ightarrow v , u ightarrow w , v ightarrow w) 在原图中同时存在。

    即需要求出原图的 三元环个数,可以参考 不常用的黑科技——「三元环」,在 (O(n log n)) 的时间求解。

    那么,(n = ?),也就是这个图的边数会不会很大呢?

    一位叫做 ( ext{shadowice1984}) 的人告诉我们边数最多只有 (760741) 条,所以就放心吧!

    对于后面的一堆东西用 整除分块 可以实现。

    对于 (n=7.5 imes 10^5),用 (n sqrt{n}) 整除分块 需要格外小心,常数很危险,需要反复卡常才能过 (cdots cdots)

    本人在卡常 (15) 次后 ( ext{AC}) 了本题。。 把几乎同样的代码不断提交

    时间复杂度:(O(n sqrt {n} imes T)).

    其中 (n leq 7.5 imes 10^5).

    期望得分:(100pts). 实际得分:(70) ~ (100pts).(取决于常数)

    如果你交我代码发现A不了,只能说你人品差了

    // i=-~i 是 i++ 的优化
    // 所有 min , max , gcd 手写卡常
    // register 寄存器用来优化
    // 一段 GCC 优化模板
    #pragma GCC optimize(1)
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize(5000)
    #pragma GCC optimize(100000000)
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #pragma GCC optimize("-fgcse")
    #pragma GCC optimize("-fgcse-lm")
    #pragma GCC optimize("-fipa-sra")
    #pragma GCC optimize("-ftree-pre")
    #pragma GCC optimize("-ftree-vrp")
    #pragma GCC optimize("-fpeephole2")
    #pragma GCC optimize("-ffast-math")
    #pragma GCC optimize("-fsched-spec")
    #pragma GCC optimize("unroll-loops")
    #pragma GCC optimize("-falign-jumps")
    #pragma GCC optimize("-falign-loops")
    #pragma GCC optimize("-falign-labels")
    #pragma GCC optimize("-fdevirtualize")
    #pragma GCC optimize("-fcaller-saves")
    #pragma GCC optimize("-fcrossjumping")
    #pragma GCC optimize("-fthread-jumps")
    #pragma GCC optimize("-funroll-loops")
    #pragma GCC optimize("-fwhole-program")
    #pragma GCC optimize("-freorder-blocks")
    #pragma GCC optimize("-fschedule-insns")
    #pragma GCC optimize("inline-functions")
    #pragma GCC optimize("-ftree-tail-merge")
    #pragma GCC optimize("-fschedule-insns2")
    #pragma GCC optimize("-fstrict-aliasing")
    #pragma GCC optimize("-fstrict-overflow")
    #pragma GCC optimize("-falign-functions")
    #pragma GCC optimize("-fcse-skip-blocks")
    #pragma GCC optimize("-fcse-follow-jumps")
    #pragma GCC optimize("-fsched-interblock")
    #pragma GCC optimize("-fpartial-inlining")
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-freorder-functions")
    #pragma GCC optimize("-findirect-inlining")
    #pragma GCC optimize("-fhoist-adjacent-loads")
    #pragma GCC optimize("-frerun-cse-after-loop")
    #pragma GCC optimize("inline-small-functions")
    #pragma GCC optimize("-finline-small-functions")
    #pragma GCC optimize("-ftree-switch-conversion")
    #pragma GCC optimize("-foptimize-sibling-calls")
    #pragma GCC optimize("-fexpensive-optimizations")
    #pragma GCC optimize("-funsafe-loop-optimizations")
    #pragma GCC optimize("inline-functions-called-once")
    #pragma GCC optimize("-fdelete-null-pointer-checks")
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const ll N=8e5+5,MOD=1e9+7;
    
    inline ll read(){char ch=getchar(); ll f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	ll x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    ll a,b,c,T,cnt,tot,ans;
    ll lst[N],d[N],p[N],mu[N],ok[N],ord[N],deg[N],f[N],from[N],to[N],lcm[N],mrk[N];
    vector<ll>v[N],w[N];
    inline ll min(ll a,ll b){return a<b?a:b;}
    inline ll max(ll a,ll b){return a>b?a:b;}
    inline ll gcd(ll a,ll b){return (!b)?a:gcd(b,a%b);}
    
    int main() {
        p[1]=mu[1]=1;
    	for(register int i=2;i<N;i=-~i) {
            if(!p[i]) lst[++cnt]=i,mu[i]=-1;
            for(register int j=1;j<=cnt;j=-~j){
                if(i*lst[j]>=N) break;
                p[i*lst[j]]=1;
                if(i%lst[j]==0) {mu[i*lst[j]]=0;break;}
                mu[i*lst[j]]=-mu[i];
            }
        } for(register int i=1;i<N;i=-~i)
            if(mu[i]) ok[++tot]=i,ord[i]=tot;
        for(register int i=1;i<N;i=-~i) {
            for(register int j=1;i*j<N;j=-~j) d[i*j]++;
            f[i]=(f[i-1]+d[i])%MOD;
        } T=read();
        while(T--) {
            memset(deg,0,sizeof(deg));
            memset(v,0,sizeof(v));
            memset(w,0,sizeof(w));
            a=read(),b=read(),c=read();
            ll mn=min(min(a,b),c),mx=max(max(a,b),c);
            ll e=ans=0;
            for(register int i=1;i<=tot;i=-~i){
                if(ok[i]>mx) break;
                for(register int j=1;j<=tot;j=-~j){
                    if(ok[i]*ok[j]>mx) break;
                    if(!mu[ok[i]*ok[j]]) continue;
                    for(register int k=j+1;k<=tot;k=-~k){
                        if(ok[i]*ok[j]*ok[k]>mx) break;
                        if(mu[ok[i]*ok[k]]==0||gcd(ok[j],ok[k])>1) continue;
                        from[++e]=ord[ok[i]*ok[j]],to[e]=ord[ok[i]*ok[k]],lcm[e]=ok[i]*ok[j]*ok[k];
                        deg[from[e]]++,deg[to[e]]++;
                    } 
                }
            }
            for(register int i=1;i<=tot;i=-~i) {
                if(ok[i]>mn) break;
                ans+=mu[ok[i]]*mu[ok[i]]*mu[ok[i]]*f[a/ok[i]]*f[b/ok[i]]*f[c/ok[i]];
            }
            for(register int i=1;i<=e;i=-~i) {
                v[from[i]].push_back(to[i]),w[from[i]].push_back(lcm[i]);
                v[to[i]].push_back(from[i]),w[to[i]].push_back(lcm[i]);
            }
            for(register int i=1;i<=tot;i=-~i) {
                if(ok[i]>min(a,b)) break;
                for(register int j=0;j<v[i].size();j=-~j) {
                    ll x=ok[i],y=ok[v[i][j]],z=w[i][j];
                    ans=(ans+mu[x]*mu[y]*mu[y]*f[a/z]*f[b/z]*f[c/y]);
                    ans=(ans+mu[x]*mu[x]*mu[y]*f[a/x]*f[b/z]*f[c/z]);
                    ans=(ans+mu[x]*mu[x]*mu[y]*f[a/z]*f[b/x]*f[c/z]);
                }
            } ans=(ans+MOD)%MOD;
            memset(v,0,sizeof(v));
            memset(w,0,sizeof(w));
            for(register int i=1;i<=e;i=-~i) {
                if(deg[from[i]]>=deg[to[i]]) v[from[i]].push_back(to[i]),w[from[i]].push_back(lcm[i]);
                else v[to[i]].push_back(from[i]),w[to[i]].push_back(lcm[i]);
            }
            for(register int i=1;i<=tot;i=-~i) {
                if(ok[i]>mx) break;
                for(register int j=0;j<v[i].size();j=-~j) mrk[v[i][j]]=w[i][j];
                for(register int j=0;j<v[i].size();j=-~j){
                    ll x=v[i][j];
                    for(register int k=0;k<v[x].size();k=-~k){
                        ll y=v[x][k],p=mrk[y],q=w[i][j],r=w[x][k];
                        if(!mrk[y]) continue;
                        ll st1,st2,st3,st4,st5,st6;
                        st1=f[a/p]*f[b/q]*f[c/r];
                        st2=f[a/p]*f[b/r]*f[c/q];
                        st3=f[a/q]*f[b/p]*f[c/r];
                        st4=f[a/q]*f[b/r]*f[c/p];
                        st5=f[a/r]*f[b/p]*f[c/q];
                        st6=f[a/r]*f[b/q]*f[c/p];
                        ans=(ans+mu[ok[i]]*mu[ok[x]]*mu[ok[y]]*(st1+st2+st3+st4+st5+st6)+MOD)%MOD;
                    }
                } for(register int j=0;j<v[i].size();j=-~j) mrk[v[i][j]]=0;
            }
            printf("%lld
    ",(ans+MOD)%MOD);
        }
        return 0;
    }
    
  • 相关阅读:
    css水平垂直居中问题
    关系型数据库四大特性
    C++读取csv文件&&收获到的知识
    恒生面试记录
    SQL数据库操作命令
    安防产品知识记录
    学会求助(带着自己的理解去和别人探讨解决方案),处理问题责任清晰,如果不清楚可以问主管.
    一个简单又不简单的socket例子
    C++面试题总结
    大华电话面试
  • 原文地址:https://www.cnblogs.com/bifanwen/p/12814426.html
Copyright © 2011-2022 走看看