洛谷P3312 - [SDOI2014]数表

Portal

Solution

\(T(T\leq2\times10^4)\)组测试数据。给出\(n,m(n,m\leq10^5),a(a\leq10^9)\),求\[ \sum_{i=1}^n\sum_{j=1}^m [\sigma_1(gcd(i,j))\leq a]\sigma_1(gcd(i,j)) \]

Solution

\[\begin{align*} ans &= \sum_{i=1}^n\sum_{j=1}^m [\sigma_1(gcd(i,j))\leq a]\sigma_1(gcd(i,j)) \\ &= \sum_{d=1}^{+∞} [\sigma_1(d)\leq a]\sigma_1(d) \sum_{i=1}^n\sum_{j=1}^m [gcd(i,j)=d] \\ &= \sum_{d=1}^{+∞} [\sigma_1(d)\leq a]\sigma_1(d) \sum_{d_1=1}^{+∞} \mu(d_1)⌊\frac{n}{dd_1}⌋⌊\frac{m}{dd_1}⌋ \\ &= \sum_{d=1}^{+∞} ⌊\frac{n}{d}⌋⌊\frac{m}{d}⌋ \sum_{d_1|d} [\sigma_1(d_1)\leq a]\sigma_1(d_1)\mu(\frac{d}{d_1}) \end{align*}\] 将测试数据按\(a\)由小到大排序,维护\(f(x)=\sum_{d|x} [\sigma_1(d)\leq a]\sigma_1(d)\mu(\dfrac{x}{d})\)的前缀和。当\(a\)\(a_1\)增大至\(a_2\)时,对于\(d\)满足\(\sigma_1(d)\in(a_1,a_2]\),将\(\sigma_1(d)\mu(k)\)加到\(f(kd)\)中。预处理出\(\sigma_1(x),\mu(x)\),用树状数组维护\(f(x)\)的前缀和即可。

时间复杂度\(O(n+T\sqrt n+nlogn)\)

Code

//[SDOI2014]数表
#include <algorithm>
#include <cstdio>
using namespace std;
inline char gc()
{
    static char now[1<<16],*s,*t;
    if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
    return *s++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
const int N=1e5+10;
const int N1=1e5;
int pCnt,pr[N],p1[N]; bool pNot[N];
int mu[N]; struct rec{int v,id;} f[N];
bool cmpV(rec x,rec y) {return x.v<y.v;}
void init(int n)
{
    mu[1]=1,f[1].v=1;
    for(int i=1;i<=n;i++) f[i].id=i;
    for(int i=2;i<=n;i++)
    {
        if(!pNot[i])
        {
            pr[++pCnt]=i; p1[i]=i;
            mu[i]=-1,f[i].v=i+1;
            for(long long j=1LL*i*i;j<=n;j*=i) f[j].v=f[j/i].v*i+1;
        }
        for(int j=1;j<=pCnt;j++)
        {
            int x=i*pr[j]; if(x>n) break;
            pNot[x]=true;
            if(i%pr[j]) p1[x]=pr[j],mu[x]=-mu[i],f[x].v=f[i].v*(pr[j]+1);
            else {p1[x]=p1[i]*pr[j],f[x].v=f[x/p1[x]].v*f[p1[x]].v; break;}
        }
    }
    sort(f+1,f+n+1,cmpV);
}
struct query{int n,m,a,id;} q[20010];
bool cmpA(query x,query y) {return x.a<y.a;}
int tr[N];
void add(int x,int v) {while(x<=N1) tr[x]+=v,x+=x&(-x);}
int sum(int x) {int r=0; while(x) r+=tr[x],x-=x&(-x); return r;}
int ans[20010];
int main()
{
    int Q=read(); init(N1);
    for(int i=1;i<=Q;i++) q[i].n=read(),q[i].m=read(),q[i].a=read(),q[i].id=i;
    sort(q+1,q+Q+1,cmpA);
    for(int i=1,j=1;i<=Q;i++)
    {
        int n=q[i].n,m=q[i].m,a=q[i].a;
        while(j<=1e5&&f[j].v<=a)
        {
            int d1=f[j].id;
            for(int k=1;k*d1<=1e5;k++) add(k*d1,f[j].v*mu[k]);
            j++;
        }
        if(n>m) swap(n,m);
        int res=0;
        for(int L=1,R;L<=n;L=R+1)
        {
            int v1=n/L,v2=m/L; R=min(n/v1,m/v2);
            res+=v1*v2*(sum(R)-sum(L-1));
        }
        ans[q[i].id]=res&2147483647;
    }
    for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
    return 0;
}

P.S.

答案对\(2147483647\)取模,这就相当于自然溢出然后&2147483647

猜你喜欢

转载自www.cnblogs.com/VisJiao/p/LgP3312.html