[bzoj3529][Sdoi2014]数表

来自FallDream的博客,未经允许,请勿转载,谢谢。


有一张N×m的数表,其第i行第j列(1 < =i < =n,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。

T<=20000组数据,n,m<=10^5

保证n<=m,f(x)表示x的因数和;

枚举gcd $$Ans=\sum_{d=1}^{n}f(d)*\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{d|i,d|j}\mu(d)$$

把d扔出来$$Ans=\sum_{d=1}^{n}f(d)*\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)*\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor$$

令$T=kd$得到$$Ans=\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T,f(d)\leqslant a}f(d)\mu(T/d)$$

前面那坨东西只有根号种取值,但是后面那东西不好计算,考虑把询问按照a排序之后插入树状数组计算答案。

复杂度$O(T\sqrt{n}logn)$

瞎写自然溢出调了半天 最后弃疗了不如取模

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MN 100000
#define ll long long
#define mod 2147483647
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int mu[MN+5],s[MN],m,num=0,Ans[MN+5];
bool b[MN+5];
ll ans=0,c[MN+5],sum;
pair<ll,int> f[MN+5];
struct ques{
    int n,m,a,id;
    bool operator<(const ques&b)const{return a<b.a;}    
}q[MN+5];

inline void ins(int x,ll ad){for(;x<=MN;x+=x&(-x)) c[x]+=ad;}
inline ll query(int x)
{
    for(sum=0;x;x-=x&(-x)) sum+=c[x];
    return sum;
}
void solve(int a)
{    
    for(int j=f[a].second;j<=MN;j+=f[a].second) 
        ins(j,f[a].first*mu[j/f[a].second]);
}

int main()
{
    mu[1]=1;
    for(int i=1;i<=MN;i++)
        for(int j=i;j<=MN;j+=i) 
            f[j].first+=i;
    for(int i=1;i<=MN;i++) f[i].second=i;
    for(int i=2;i<=MN;i++)
    {
        if(!b[i]) s[++num]=i,mu[i]=-1;
        for(int j=1;s[j]*i<=MN;j++)
        {
            b[s[j]*i]=1;
            if(i%s[j]==0)break;
            mu[s[j]*i]=-mu[i];
        }
    }
    sort(f+1,f+MN+1);
    m=read();    
    for(int i=1;i<=m;i++) 
    {
        q[i].n=read(),q[i].m=read();
        if(q[i].n>q[i].m) swap(q[i].n,q[i].m);
        q[i].a=read();q[i].id=i;
    }
    sort(q+1,q+m+1);
    for(int i=1,j=1;i<=m;i++)
    {
        for(;f[j].first<=(ll)q[i].a&&j<=MN;++j) solve(j);ans=0; 
        for(int j=1,last;j<=q[i].n;j=last+1)
        {
            last=min(q[i].m/(q[i].m/j),q[i].n/(q[i].n/j));
            ans+=((1LL*(query(last)-query(j-1))*(q[i].n/j))&mod)*(q[i].m/j);
            ans&=mod;
        }
        Ans[q[i].id]=ans;
    }
    for(int i=1;i<=m;i++) printf("%d\n",Ans[i]);
    return 0;
}

 

posted @ 2017-04-21 11:07  FallDream  阅读(296)  评论(0编辑  收藏  举报