• [SDOI2014]数表


    题目链接

    题意很明确。

    题目不是很难,先讲讲正解,再分享一下我的一些想法(下面默认(n<m))

    首先记(sigma(x))(x)因数和

    我们先不考虑a的影响,则题目所求的式子为

    [sum^{n}_{x=1}{sum^{m}_{y=1} {sigma(gcd(i,j)) }} ]

    显然我们枚举gcd

    [sum^{n}_{d=1}sum^{n}_{x=1}{sum^{m}_{y=1} {sigma(d)[gcd(i,j)==d] }} ]

    [sum^{n}_{d=1}sigma(d)sum^{lfloor frac{n} {d} floor}_{x=1}{sum^{lfloor frac{m} {d} floor}_{y=1} {[gcd(i,j)==1] }} ]

    [sum^{n}_{d=1}sigma(d)sum^{lfloor frac{n} {d} floor}_{x=1}{sum^{lfloor frac{m} {d} floor}_{y=1} {sum_{t|gcd(i,j)}mu(t) }} ]

    [sum^{n}_{d=1}sigma(d) {sum^{lfloor frac{n} {d} floor}_{t=1}mu(t)sum^{lfloor frac{n} {td} floor}_{x=1}{sum^{lfloor frac{m} {td} floor}_{y=1}1}} ]

    [sum^{n}_{d=1}sigma(d) {sum^{lfloor frac{n} {d} floor}_{t=1}mu(t)lfloor frac{n} {td} floorlfloor frac{m} {td} floor} ]

    (s)=(t*d)

    [sum^{n}_{s=1}lfloor frac{n} {s} floorlfloor frac{m} {s} floor {sum_{d|s}sigma(d)mu(frac{s}{d})} ]

    前面的可以整除分块,那后面呢?

    我们设(f(s)={sum_{d|s}sigma(d)mu(frac{s}{d})})

    然后只要求出(f)的前缀和就(ok)

    别忘了还有一个a呢

    欸,好像只要(sigma(gcd(i,j)))(leq)(a)就准保没事

    (d=gcd(i,j))

    也就是说(sigma(d))(leq)(a)才会给(f(s))做贡献

    我们随便就可以求出(sigma(d))(n)项的值 (O)((n)) (O(n*log n))随便跑

    然后我们离线做,将输入的按(a)升序排列,(sigma(x))也升序排列

    然后对于所有的(sigma(d)leq a)的我梦将他扩倍,换言之就是找所有的(d|s)中的(s)(sigma(d)mu(frac{s}{d})) 加到(s)这个地方

    单点插入,求前缀和,使用树状数组维护就行了

    正解讲完了!!


    谈谈我的一些其他想法

    我最开始第一步都不是不是这么做的,显然死在半路上了

    然后看自己第一步和最后一步都与大多题解都不一样时,我是自闭的

    但其实是一样的。。

    我的做法,也先不考虑(a)

    [sum ^{n}_{i=1}sum ^{m}_{j=1}sum^{n}_{t=1}[t|i]\,[t|j] imes t ]

    [sum ^{n}_{t=1}tsum ^{lfloor frac{n}{t} floor}_{i=1}sum^{lfloor frac{m}{t} floor}_{j=1}1 ]

    [sum ^{n}_{t=1}tlfloor frac{n}{t} floorlfloor frac{m}{t} floor ]

    写到这看到题解我就懵了,因为得出结论

    [t={sum_{d|s}sigma(d)mu(frac{s}{d})} ]

    当时我以为我推错了 但他是对的!!

    为啥呢?

    首先大家都知道迪利克雷卷积

    几个常见的结论

    [varphi * 1 = id ]

    [mu * id = varphi ]

    [mu * 1 =varepsilon ]

    [id *1 = sigma ]

    同时他也有交换律,结合律
    (mu*id*1=varphi *1)

    ((mu*1)*id=varphi*1)

    (varepsilon*id=id)

    显然单位元乘(id)肯定等于(id),最后结论显然成立

    所以我的和正解的式子是相同的

    (没发现还是我太菜)

    最后上代码了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll N=1e5+10,M=1e5,mod=1ll<<31ll;
    ll mu[N],pr[N],p[N],tot,t[N],T,ans[N],n,m,a;
    struct node{ll n,m,a,id;}h[N];
    pair<ll,ll> s[N];
    inline int cmp(node a,node c){return a.a<c.a;}
    template<class T>void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x=f?-x:x;
    }
    inline void insert(ll x,ll v)
    {
        for(int i=x;i<=M;i+=(i)&(-i)) t[i]+=v;
    }
    inline ll query(ll x)
    {
        ll k=0;
        for(int i=x;i>0;i-=(i)&(-i)) k+=t[i];
        return k%mod;
    }
    int main()
    {
        mu[1]=1;
        for(int i=2;i<=M;i++)
        {
            if(!pr[i]) p[++tot]=i,mu[i]=-1;
            for(int j=1;p[j]*i<=M&&j<=tot;j++)
            {
                pr[i*p[j]]=1;
                if(i%p[j]==0) break;
                mu[i*p[j]]=-mu[i];
            }
        }
        for(int i=1;i<=M;i++)
        {
            s[i].second=i;
            for(register int d=1;d<=M/i;d++)
                s[i*d].first+=d;
        }
        read(T);
        for(register int i=1;i<=T;i++) read(h[i].n),read(h[i].m),read(h[i].a),h[i].id=i;
        sort(s+1,s+1+M);
        sort(h+1,h+1+T,cmp);
        for(int i=1,j=1;i<=T;i++)
        {
            n=h[i].n,m=h[i].m,a=h[i].a;
            while(s[j].first<=a&&j<=M)
            {
                for(ll d=1;d*s[j].second<=M;d++)
                    insert(d*s[j].second,s[j].first*mu[d]);
                j++;
            }
            
            if(n>m) swap(n,m);
            for(int l=1,r=1;l<=n;l=r+1)
            {
                r=min(n/(n/l),m/(m/l));
                ans[h[i].id]+=(n/l)*(m/l)*(query(r)-query(l-1));
            }
            ans[h[i].id]%=mod;
        }
        for(int i=1;i<=T;i++) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    博客的开端,找对象不再new
    OpenGL编程 基础篇(六)OpenGL中几种光照参数
    OpenGL编程 基础篇(五)世界窗口和视口
    百练2952:循环数
    百练2811:熄灯问题
    百练2812:恼人的青蛙
    百练3177:判决素数个数
    百练1248:Safecracker
    OpenGL编程 基础篇(四)与鼠标的交互
    OpenGL编程 基础篇(三)用点集绘制函数
  • 原文地址:https://www.cnblogs.com/Phoenix41/p/12274669.html
Copyright © 2020-2023  润新知