3529: [Sdoi2014]数表

来源:互联网 发布:区块链的共识机制 算法 编辑:程序博客网 时间:2024/05/16 08:27

3529: [Sdoi2014]数表

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1186  Solved: 604
[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

Round 1 Day 1

[Submit][Status][Discuss]


HOME Back


莫比乌斯反演,,默认n <= m

令F[i] = i的所有约数和

题目要求的即是∑F[i] (F[i] <= a)

先忽略a的限制

换个思路,令f[i] = 以i为最大公约数的对数

ans = ∑f[i]*F[I] = ∑F[i]*∑u(d/i)*[n/d]*[m/d]   (i|d)

转换一下

ans = ∑[n/d]*[m/d]∑F[i]*u(d/i)   只要想办法处理好∑F[i]*u(d/i) 的前缀和,每次询问就能在根号n内完成

现在有了a的限制,,

先读入所有询问,按照a排序,我们需要的只有F[i] <= a的F

前缀和什么的,树状数组就行

每次要新增F的时候,根据公式,只需要维护i的每个倍数就行

至于F,用筛法O(nlogn),毕竟∑(n/i) = nlogn



嗯,,对∑的运算不够熟练,这个公式拆了好久,,GG

然后,第一次写的时候居然一边做一边取模,强行T一发

(明明把所有数字的约数合起来都不会爆long long啊)

#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#include<cmath>#include<vector>#include<queue>#include<stack>using namespace std;typedef long long LL;const int maxn = 1E5 + 10;const LL mo = (1LL<<31LL);struct data{LL F; int pos;bool operator < (const data &b) const {return F < b.F;}}f[maxn];struct Q{int n,m,a,num;Q(int _n = 0,int _m = 0,int _a = 0,int _num = 0) {n = _n; m = _m; a = _a; num = _num;}bool operator < (const Q &b) const {return a < b.a;}}query[maxn];int T,ans[maxn];LL c[maxn],mu[maxn];bool not_prime[maxn];void Add(LL F,int pos){for (int i = 1; i*pos < maxn; i++) for (int j = i*pos; j < maxn; j += j&-j)c[j] += F*mu[i];}LL sum(int pos){LL ret = 0;for (; pos > 0; pos -= pos&-pos)ret += c[pos];return ret;}int Work(LL n,LL m){int last,tail = min(n,m);LL ret = 0;for (LL i = 1; i <= tail; i = last + 1) {last = min(n/(n/i),m/(m/i));ret += (n/i)*(m/i)*(sum(last) - sum(i-1));}return ret%mo;}int main(){#ifdef DMC   freopen("DMC.txt","r",stdin);#endiffor (int i = 1; i < maxn; i++) mu[i] = 1;for (int i = 2; i < maxn; i++)if (!not_prime[i]) {mu[i] = -1;for (int j = 2; j*i < maxn; j++) {mu[j*i] *= mu[i];if (j % i == 0) mu[j*i] = 0;not_prime[j*i] = 1;}}for (int i = 1; i < maxn; i++) {f[i].pos = i;for (int j = 1; j*i < maxn; j++) f[j*i].F += 1LL*i;}sort(f + 1,f + maxn);cin >> T;for (int i = 1; i <= T; i++) {int x,y,z; scanf("%d%d%d",&x,&y,&z);query[i] = Q(x,y,z,i);}sort(query + 1,query + T + 1);int tail = 1;for (int i = 1; i <= T; i++) {while (tail < maxn && f[tail].F <= query[i].a) Add(f[tail].F,f[tail].pos),++tail;ans[query[i].num] = Work(query[i].n,query[i].m);}for (int i = 1; i <= T; i++) printf("%d\n",ans[i]);return 0;}


0 0
原创粉丝点击