P3312 [SDOI2014]数表

孤街浪徒 提交于 2019-12-05 23:36:31

题意

默认\(n\leqslant m\)

\(f(i)\)表示\(i\)的约数和,因为是积性函数,可以用线性筛求。

先不考虑\(a\)的限制,我们推下式子:
\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}f(\gcd(i,j))\)
枚举\(\gcd(i,j)\)
\(\sum\limits_{d=1}^{n}f(d)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[\gcd(i,j)=d]\)
之后就莫反:
\(\sum\limits_{d=1}^{n}f(d)\sum\limits_{i=1}^{\frac{n}{d}}\sum\limits_{j=1}^{\frac{m}{d}}[\gcd(i,j)=1]\)
\(\sum\limits_{d=1}^{n}f(d)\sum\limits_{i=1}^{\frac{n}{d}}\sum\limits_{j=1}^{\frac{m}{d}}\sum\limits_{x|\gcd(i,j)}\mu(x)\)
\(\sum\limits_{d=1}^{n}f(d)\sum\limits_{x=1}^{\frac{n}{d}}\mu(x)\sum\limits_{i=1}^{\frac{n}{d}}\sum\limits_{j=1}^{\frac{m}{d}}[x|\gcd(i,j)]\)
\(\sum\limits_{d=1}^{n}f(d)\sum\limits_{x=1}^{\frac{n}{d}}\mu(x)*\frac{n}{d*x}*\frac{m}{d*x}\)
\(T=d*x\)
\(\sum\limits_{T=1}^{n}\frac{n}{T}*\frac{m}{T}\sum\limits_{d|T}f(d)*\mu(\frac{T}{d})\)
除法分块加预处理\(\sum\limits_{d|T}f(d)*\mu(\frac{T}{d})\)即可。

对于\(a\)的限制,我们离线按\(a\)排序,同时用树状数组维护即可。

code:

#include<bits/stdc++.h>
using namespace std;
#define pli pair<ll,int>
#define mkp make_pair
#define fir first
#define sec second
typedef long long ll;
const int maxn=1e5+10;
const int maxq=2*1e4+10;
const ll mod=2147483648;
int Q;
int mu[maxn];
ll g[maxn],ans[maxq];
bool vis[maxn];
pli f[maxn];
vector<int>prime;
struct Query{int n,m,lim,id;}qr[maxq];
struct Tree_arry
{
    #define lowbit(x) (x&-x)
    ll a[maxn];
    inline void add(int x,ll k){for(int i=x;i<=100000;i+=lowbit(i))a[i]=(a[i]+k)%mod;}
    inline ll query(int x){ll res=0;for(int i=x;i;i-=lowbit(i))res=(res+a[i])%mod;return res;}
}tr;
inline bool cmp(Query x,Query y){return x.lim<y.lim;}
inline void pre_work(int n)
{
    mu[1]=1;f[1]=mkp(1,1);vis[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i])prime.push_back(i),mu[i]=-1,f[i]=mkp(i+1,i),g[i]=i+1;
        for(unsigned int j=0;j<prime.size()&&i*prime[j]<=n;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                g[i*prime[j]]=g[i]*prime[j]+1;
                f[i*prime[j]]=mkp(f[i].fir/g[i]*g[i*prime[j]],i*prime[j]);
                break;
            }
            mu[i*prime[j]]=-mu[i];
            f[i*prime[j]]=mkp(f[i].fir*f[prime[j]].fir,i*prime[j]);
            g[i*prime[j]]=prime[j]+1;
        }
    }
}
inline void work(int x)
{
    for(int i=1;i*f[x].sec<=100000;i++)tr.add(i*f[x].sec,(f[x].fir*mu[i]%mod+mod)%mod);
}
inline ll calc(int n,int m)
{
    ll res=0;
    if(n>m)swap(n,m);
    for(int l=1,r;l<=n;l=r+1)
    {
        r=min(n/(n/l),m/(m/l));
        res=(res+((tr.query(r)-tr.query(l-1))%mod+mod)%mod*(n/l)%mod*(m/l)%mod)%mod;
    }
    return res;
}
int main()
{
    pre_work(100000);
    sort(f+1,f+100000+1);
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++)scanf("%d%d%d",&qr[i].n,&qr[i].m,&qr[i].lim),qr[i].id=i;
    sort(qr+1,qr+Q+1,cmp);
    for(int i=1,j=1;i<=Q;i++)
    {
        while(f[j].fir<=qr[i].lim&&j<=100000)work(j),j++;
        ans[qr[i].id]=calc(qr[i].n,qr[i].m);
    }
    for(int i=1;i<=Q;i++)printf("%lld\n",ans[i]);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!