BZOJ 3529: [Sdoi2014]数表

Description

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

HINT

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

Solution

先假设a的限制不存在

正面把答案强行写出来是这样的

其中F(i)为i的约数和,可以线性筛处理

然后慢慢化简其中的各个部分

令g(i)为1<=x<=n,1<=y<=m,gcd(x,y)=i的数对(x,y)的个数

则有

用莫比乌斯反演代换

此时知需要一个的前缀和就可以继续愉快地分块了

然而此时还有a的限制,怎么继续做前缀和?

如果我们可以每次求前缀和的时候都只选择F( i )比a小的就好了

此时想到其实还有一种前缀和的方法树状数组,并且可以以加入的顺序控制前缀和

于是自然地离线询问,按a值排序,按F( i )排序后依次加入树状数组

取模用了PoPoQQQ的自然溢出

  1 #include<map>
  2 #include<cmath>
  3 #include<ctime>
  4 #include<queue>
  5 #include<stack>
  6 #include<cstdio>
  7 #include<climits>
  8 #include<iomanip>
  9 #include<cstring>
 10 #include<cstdlib>
 11 #include<iostream>
 12 #include<algorithm>
 13
 14 #define maxp 100000
 15 #define maxn 100000+5
 16 #define set(a,b) memset(a,(b),sizeof(a))
 17 #define fr(i,a,b) for(ll i=(a),_end_=(b);i<=_end_;i++)
 18 #define rf(i,b,a) for(ll i=(a),_end_=(b);i>=_end_;i--)
 19 #define fe(i,a,b) for(int i=first[(b)],_end_=(a);i!=_end_;i=s[i].next)
 20 #define fec(i,a,b) for(int &i=cur[(b)],_end_=(a);i!=_end_;i=s[i].next)
 21
 22 using namespace std;
 23
 24 typedef long long ll;
 25
 26 struct sigma{
 27   int number,F;
 28 }s[maxn];
 29
 30 struct query{
 31   int n,m,a;
 32   int number;
 33 }q[maxn];
 34
 35 int bit[maxn];
 36 int prime[maxn],pri[maxn],miu[maxn];
 37 int ans[maxn],tot=0,st=1;
 38 int T;
 39
 40 void read()
 41 {
 42 #ifndef ONLINE_JUDGE
 43   freopen("3529.in","r",stdin);
 44   freopen("3529.out","w",stdout);
 45 #endif
 46   //cin >> T ;
 47   scanf("%d",&T);
 48 }
 49
 50 void write()
 51 {
 52   fr(i,1,T)
 53     //cout << (ans[i]&0x7fffffff) << endl ;
 54     printf("%d\n",ans[i]&0x7fffffff);
 55 }
 56
 57 void get()
 58 {
 59   miu[1]=1;
 60   fr(i,2,maxp){
 61     if( !prime[i] ) pri[++tot]=i,miu[i]=-1;
 62     int j=1;
 63     while( j<=tot && pri[j]*i<=maxp ){
 64       prime[i*pri[j]]=1;
 65       if( i%pri[j]==0 ){
 66     miu[i*pri[j]]=0;
 67     break;
 68       }
 69       miu[i*pri[j]]=-miu[i];
 70       j++;
 71     }
 72   }
 73   fr(i,1,maxp){
 74     fr(j,1,maxp/i)
 75       s[i*j].F+=i;
 76     s[i].number=i;
 77   }
 78 }
 79
 80 bool comp(sigma a,sigma b)
 81 {
 82   return a.F<b.F;
 83 }
 84
 85 bool cmp(query a,query b)
 86 {
 87   return a.a<b.a;
 88 }
 89
 90 void add(int x,int w)
 91 {
 92   while( x<=maxp ){
 93     bit[x]+=w;
 94     x+=x&-x;
 95   }
 96 }
 97
 98 int sum(int x)
 99 {
100   int res=0;
101   while( x>0 ){
102     res+=bit[x];
103     x-=x&-x;
104   }
105   return res;
106 }
107
108 int calc(int x,int y)
109 {
110   if( x>y ) swap(x,y);
111   int res=0,pos;
112   int i=1;
113   while( i<=x ){
114     pos=min((x/(x/i)),(y/(y/i)));
115     res+=(sum(pos)-sum(i-1))*(x/i)*(y/i);
116     i=pos+1;
117   }
118   return res;
119 }
120
121 void work()
122 {
123   fr(i,1,T){
124     //cin >> q[i].n >> q[i].m >> q[i].a ;
125     scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a);
126     q[i].number=i;
127   }
128   get();
129   sort(q+1,q+T+1,cmp);
130   sort(s+1,s+maxp+1,comp);
131   fr(i,1,T){
132     while( st<=maxp && s[st].F<=q[i].a ){
133       fr(j,1,maxp/s[st].number)
134     add(s[st].number*j,s[st].F*miu[j]);
135       st++;
136     }
137     ans[q[i].number]=calc(q[i].n,q[i].m);
138   }
139 }
140
141 int main()
142 {
143   read();
144   work();
145   write();
146   return 0;
147 }
时间: 2024-12-11 11:22:28

BZOJ 3529: [Sdoi2014]数表的相关文章

BZOJ 3529: [Sdoi2014]数表 [莫比乌斯反演 树状数组]

3529: [Sdoi2014]数表 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1399  Solved: 694[Submit][Status][Discuss] Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. Input 输入包含多组数据.    输入的第一行一个整数Q表示测试点内的数据

BZOJ 3529([Sdoi2014]数表-莫比乌斯反演)

有一张N×m的数表,其第i行第j列(1 < =i < =n,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和模2^31的值模2^31的值. 1<=n.m<=10 5 ,Q<=2×10 4  组询问 记k的约数和f(k) 求∑ n i=1 ∑ m j=1 gcd(i,j)[f(gcd(i,j))≤a] #include<bits/stdc++.h> using namespace std; #defin

●BZOJ 3529 [Sdoi2014]数表

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3529 题解: 莫比乌斯反演. 按题目的意思,令$f(i)$表示i的所有约数的和,就是要求: $ANS=\sum f(gcd(i,j)),满足1 \leq i \leq n,1 \leq j \leq m,且 f(gcd(i,j))\leq a$ 首先 $f(i)$ 应该还是比较好推的,利用其为积性函数的特点,可以在线性筛时完成计算. 令$g[k]$表示$gcd(i,j)=k$的$(i,j)

bzoj 3529 [Sdoi2014]数表 (莫比乌斯反演+树状数组+离线)

题目大意:有一张$n*m$的数表,第$i$行第$j$列的数是同时能整除$i,j$的所有数之和,求数表内所有不大于A的数之和 先是看错题了...接着看对题了发现不会做了...刚了大半个下午无果 看了Po姐的题解(Orzzz)才搞懂这道题,搞清楚了莫比乌斯反演的两种经典的卷积形式的不同之处 令$\sigma(i)$表示i的约数个数和 如果去掉A这个限制,则题目是让我们求$\sum_{i=1}^{n}\sum_{j=1}^{m}\sigma(gcd(i,j))$ 考虑如何正确转化式子,让我们能够把不大

【BZOJ】3529: [Sdoi2014]数表

题意:求 $$\sum_{i=1}^{n} \sum_{j=1}^{m} \sum_{d|(i, j)} d 且 (\sum_{d|(i, j)} d)<=a$$ n, m<=1e5,q次询问,q<=2*1e4 #include <bits/stdc++.h> using namespace std; const int N=1e5+10, MN=1e5, YU=(1u<<31)-1; int c[N], mx; void upd(int x, int s) {

bzoj [SDOI2014]数表 莫比乌斯反演 BIT

bzoj [SDOI2014]数表 莫比乌斯反演 BIT 链接 bzoj luogu loj 思路 \[ \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}a*[f[gcd(i,j)]<=a] \] \[ f[]可以O(n)预处理出来 \] \[ \sum\limits_{k=1}^{n}f[k]*\sum\limits_{i=1}^{m}\sum\limits_{j=1}^{m}[gcd(i,j)==k] \] \[ \sum\limits_{k=1}^{n}

【BZOJ3529】[Sdoi2014]数表 莫比乌斯反演+树状数组

[BZOJ3529][Sdoi2014]数表 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 I

P3312 [SDOI2014]数表

P3312 [SDOI2014]数表 求\(\sum_{i=1}^n\sum_{j=1}^m\sigma(gcd(i,j))[\sigma(gcd(i,j)<=a)]\) \(f(d)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]\) \(F(d)=\sum_{i=1}^n\sum_{j=1}^m [|dgcd(i,j)]=\sum_{d|k}f(k)\) \(f(d)=\sum_{d|k}\mu(\dfrac{k}{d})F(k)=\sum_{d|k}\mu(\le

数表(bzoj 3529)

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 Sa