[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} \rfloor}_{x=1}{\sum^{\lfloor \frac{m} {d} \rfloor}_{y=1} {[gcd(i,j)==1] }} \]

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

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

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

\(s\)=\(t*d\)

\[\sum^{n}_{s=1}\lfloor \frac{n} {s} \rfloor\lfloor \frac{m} {s} \rfloor {\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]\times t \]

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

\[\sum ^{n}_{t=1}t\lfloor \frac{n}{t}\rfloor\lfloor \frac{m}{t}\rfloor \]

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

\[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\n",ans[i]);
}
posted @ 2020-02-07 21:32  Cage123  阅读(110)  评论(0编辑  收藏  举报