BZOJ[Sdoi2014]数表 莫比乌斯反演

[Sdoi2014]数表

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2383  Solved: 1229
[Submit][Status][Discuss]

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

 

 http://wenku.baidu.com/view/fbec9c63ba1aa8114431d9ac.html
 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<set>
 6 #include<ctime>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<map>
11 #include<cmath>
12 #define inf 1000000000
13 #define pa pair<int,int>
14 #define ll long long 
15 using namespace std;
16 int read()
17 {
18     int x=0,f=1;char ch=getchar();
19     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
20     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
21     return x*f;
22 }
23 int Q,mx,cnt;
24 struct data{
25     int n,m,a,id;
26 }q[40005];
27 bool mark[100005];
28 int pri[100005],mu[100005],t[100005];
29 int ans[40005];
30 pair<int,int> F[100005];
31 bool operator<(data a,data b)
32 {
33     return a.a<b.a;
34 }
35 void add(int x,int val)
36 {
37     for(int i=x;i<=mx;i+=i&-i)t[i]+=val;
38 }
39 int query(int x)
40 {
41     int tmp=0;
42     for(int i=x;i;i-=i&-i)tmp+=t[i];
43     return tmp;
44 }
45 void pre()
46 {
47     mu[1]=1;
48     for(int i=2;i<=mx;i++)
49     {
50         if(!mark[i])pri[++cnt]=i,mu[i]=-1;
51         for(int j=1;j<=cnt&&pri[j]*i<=mx;j++)
52         {
53             mark[pri[j]*i]=1;
54             if(i%pri[j]==0){mu[pri[j]*i]=0;break;}
55             else mu[pri[j]*i]=-mu[i];
56         }
57     }
58     for(int i=1;i<=mx;i++)
59         for(int j=i;j<=mx;j+=i)
60             F[j].first+=i;
61     for(int i=1;i<=mx;i++)F[i].second=i;
62 }
63 void solve(int x)
64 {
65     int id=q[x].id,n=q[x].n,m=q[x].m;
66     for(int i=1,j;i<=q[x].n;i=j+1)
67     {
68         j=min(n/(n/i),m/(m/i));
69         ans[id]+=(n/i)*(m/i)*(query(j)-query(i-1));
70     }
71 }
72 int main()
73 {
74     Q=read();
75     for(int i=1;i<=Q;i++)
76     {
77         q[i].n=read();q[i].m=read();q[i].a=read();q[i].id=i;
78         if(q[i].n>q[i].m)swap(q[i].n,q[i].m);
79         mx=max(mx,q[i].n);
80     }
81     pre();
82     sort(q+1,q+Q+1);
83     sort(F+1,F+mx+1);
84     int now=0;
85     for(int i=1;i<=Q;i++)
86     {
87         while(now+1<=mx&&F[now+1].first<=q[i].a)
88         {
89             now++;
90             for(int j=F[now].second;j<=mx;j+=F[now].second)
91                 add(j,F[now].first*mu[j/F[now].second]);
92         }
93         solve(i);
94     }
95     for(int i=1;i<=Q;i++)
96         printf("%d\n",ans[i]&0x7fffffff);
97 }

 

转载于:https://www.cnblogs.com/fengzhiyuan/p/8530876.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值