当前位置: 代码迷 >> 综合 >> BZOJ 3529 [Sdoi2014] 数表
  详细解决方案

BZOJ 3529 [Sdoi2014] 数表

热度:82   发布时间:2024-01-19 02:16:18.0

Description

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

Input

    输入包含多组数据。
    输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。

Output

    对每组数据,输出一行一个整数,表示答案模2^31的值。

Sample Input

2
4 4 3
10 10 5

Sample Output

20
148

HINT

1 < =N.m < =10^5  , 1 < =Q < =2×10^4

Source

Round 1 Day 1

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

莫比乌斯反演+树状数组~

讲解详见:https://wenku.baidu.com/view/fbec9c63ba1aa8114431d9ac.html,orz PoPoQQQ

miu[1]=1!!!


#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;int t,maxx,miu[100001],c[100001],num[100001],z[100001],now,ans[20001];
bool b[100001];
pair<int,int> f[100001];struct node{int n,m,a,id;
}q[20001];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<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;
}void add(int u,int v)
{for(int i=u;i<=maxx;i+=i&(-i)) z[i]+=v;
}int get(int u)
{int now=0;for(int i=u;i;i-=i&(-i)) now+=z[i];return now;
}bool operator < (node u,node v)
{return u.a<v.a;
}int main()
{t=read();for(int i=1;i<=t;i++){q[i].n=read();q[i].m=read();q[i].a=read();q[i].id=i;if(q[i].n>q[i].m) swap(q[i].n,q[i].m);maxx=max(maxx,q[i].n);}miu[1]=1;for(int i=2;i<=maxx;i++){if(!b[i]) c[++c[0]]=i,miu[i]=-1;for(int j=1;j<=c[0] && c[j]*i<=maxx;j++){b[c[j]*i]=1;if(i%c[j]) miu[i*c[j]]=-miu[i];else break;}}for(int i=1;i<=maxx;i++)for(int j=i;j<=maxx;j+=i) f[j].first+=i;for(int i=1;i<=maxx;i++) f[i].second=i;sort(q+1,q+t+1);sort(f+1,f+maxx+1);for(int i=1;i<=t;i++){while(now<maxx && f[now+1].first<=q[i].a){now++;for(int j=f[now].second;j<=maxx;j+=f[now].second)add(j,f[now].first*miu[j/f[now].second]);}int ne,n=q[i].n,m=q[i].m,id=q[i].id;for(int i=1;i<=n;i=ne){ne=min(n/(n/i),m/(m/i))+1;ans[id]+=(get(ne-1)-get(i-1))*(n/i)*(m/i);}}for(int i=1;i<=t;i++) printf("%d\n",ans[i]&0x7fffffff);return 0;
}