您的位置:首页 > 其它

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

2015-04-01 10:35 411 查看

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

【分析】

其实是个比较水的题目。

$\sum\limits_{i < = n\ {\rm{ j < = m}}}^{} { F(gcd(i,j))} $其中gcd(i,j) <= a,F(i),为i的因子和。
我们可以将公式变形,先忽略gcd(i, j) <= a这个条件。
$\sum\limits_{i = 1}^{\min (n,m)} {F(i) \times num(i)} $ num(i)为i在 gcd(i,j) (i <=n, j <= m)中出现的次数。
易得:
$num(i) = \sum\limits_{i|d} {\mu (\frac{d}{i}) \times \left\lfloor {\frac{n}{d}} \right\rfloor } \times \left\lfloor {\frac{m}{d}} \right\rfloor $
然后原式可以化为:
$\sum\limits_{i = 1}^{\min (n,m)} {F(i)} \times \sum\limits_{i|d} {\mu (\frac{d}{i}) \times \left\lfloor {\frac{n}{d}} \right\rfloor } \times \left\lfloor {\frac{m}{d}} \right\rfloor$
换元:
$\sum\limits_{d = 1}^{\min (n,m)} {\left\lfloor {\frac{m}{d}} \right\rfloor \left\lfloor {\frac{m}{d}} \right\rfloor } \sum\limits_{i|d} {F(i)\mu (\frac{d}{i})} $
然后再把$\sum\limits_{i|d} {F(i)\mu (\frac{d}{i})} $预处理出来,对询问以a为关键字排序,用树状数组记录一段的和,前面用分块,然后就可以做了。

/*
唐代杜牧的《遣怀》
落魄江南载酒行,楚腰纤细掌中轻。
十年一觉扬州梦,赢得青楼薄幸名。
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <iostream>
#include <string>
#include <ctime>
#include <map>
#include <set>
#define LOCAL
long long MOD = 1000000000 + 7;
const int MAXM = 1000 * 1000 + 10;
const int MAXN = 100000 + 10;
using namespace std;
//输入输出优化
int read(){
int x = 0, flag = 1;
char ch = getchar();
while (ch < '1' || ch >'9') {if (ch == '-') flag = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + (ch - '0'); ch = getchar();}
return x * flag;
}
struct FF{
int order;//order表示该num对应的gcd值
int num;
bool operator < (const FF &b)const{
return num < b.num;
}
}F[MAXN];
struct QUERY{
int l, r, a, order;
bool operator < (const QUERY &b)const{
return a < b.a;
}
}q[MAXN];
int mu[MAXN], prime[MAXN];
int g[MAXN], C[MAXN], Q, Ans[MAXN];

int lowbit(int x){return x & -x;}
void add(int x, int val){
while (x <= 100000){
C[x] += val;
x += lowbit(x);
}
return;
}
int sum(int x){
int cnt = 0;
while (x > 0){
cnt += C[x];
x -= lowbit(x);
}
return cnt;
}
void prepare(){
memset(prime, 0, sizeof(prime));
memset(C, 0, sizeof(C));

mu[1] = 1;
for (int i = 2;i <= 100000; i++){
if (!prime[i]){
prime[++prime[0]] = i;
mu[i] = -1;
}
for (int j = 1; j <= prime[0]; j++){
if (i * prime[j] > 100000) break;
prime[i * prime[j]] = 1;
if (i % prime[j] == 0){
mu[i * prime[j]] = 0;
break;
}else mu[i * prime[j]] = -mu[i];
}
}
//F[i]代表i的因数和
F[1].num = F[1].order = 1;
for (int i = 2; i <= 100000; i++){
int cnt = 0;
for (long long j = 1; j * (long long)j <= (long long)i; j++){
if (j * j == i){cnt += j; break;}
if (i % j != 0) continue;
cnt += j + (i / j);
}
F[i].num = cnt;
F[i].order = i;
}
sort(F + 1, F + 1 + 100000);
//for (int i = 1; i <= 100; i++) printf("%d\n", mu[i]);
}
void init(){
scanf("%d", &Q);
for (int i = 1; i <= Q; i++){
int l = read(), r = read(), a = read();
q[i].l = l; q[i].r = r;
q[i].a = a; q[i].order = i;
}
sort(q + 1, q + 1 + Q);
}
//直接回答第x个询问
int query(int x){
int cnt = 0;
for (int i = 1; i <= min(q[x].l, q[x].r); i++){
int t = min(q[x].l / (q[x].l / i), q[x].r / (q[x].r / i));
cnt += (q[x].l / i) * (q[x].r / i) * (sum(t) - sum(i - 1));
i = t;
}
return cnt;
}
void work(){
int pos = 1;//表示a现在的大小
for (int i = 1; i <= Q; i++){
while (F[pos].num <= q[i].a && pos <= 100000){
for (int j = 1; j * F[pos].order <= 100000; j++)
add(j * F[pos].order, F[pos].num * mu[j]);
pos++;
}
Ans[q[i].order] = query(i);
}
for (int i = 1; i <= Q; i++) printf("%d\n", Ans[i] & 0x7fffffff);
}

int main(){
int T;

prepare();
init();
work();
return 0;
}


View Code

(∑k=1nakbk)2≤(∑k=1na2k)(∑k=1nb2k)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: