zoukankan      html  css  js  c++  java
  • [bzoj3529] [Sdoi2014]数表

    Description

    有一张 n×m 的数表,其第 i 行第 j 列(1 <= i <= n, 1 <= j <= m)的数值为

    能同时整除 i 和 j 的所有自然数之和。给定 a , 计算数表中不大于 a 的数之和。

    Input

    输入包含多组数据。

    输入的第一行一个整数Q表示测试点内的数据组数

    接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。

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

    Output

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

    Sample Input

    2
    4 4 3
    10 10 5
    

    Sample Output

    20
    148
    

    solution

    前置知识:莫比乌斯反演

    首先忽略(a)这个条件,题目让求的是:

    [ans=sum_{i=1}^nsum_{j=1}^mf(gcd(i,j)) ]

    其中,(f(x))表示(x)的约数和。

    然后,我们可以莫比乌斯反演一波,得到:

    [ans=sum_{T=1}^{min(n,m)}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floorsum_{d|T}f(d)mu(frac{T}{d}) ]

    然后把后面那块设为(g),即:

    [g(n)=sum_{d|n}f(d)mu(frac{n}{d}) ]

    如果没有a的限制,随便搞搞这题就做完了。

    然后很显然可以发现,当(f(d)leqslant a)时,(f(d))才会对(g(n))有贡献。

    考虑离线,对读入按(a)排序,然后从小到大更新(g)

    由于数论分块的时候需要的是前缀和,所以可以考虑拿个数据结构维护下,这里树状数组就是个很好的选择。

    然后其他的函数线筛或者大力算一下都行。

    时间复杂度:(O(n+n*log^2(n)+q*sqrt{n}*log(n)))

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int unsigned int 
    
    void read(int &x) {
    	x=0;int f=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
    	if(x<0) x=-x,putchar('-');
    	if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e5+1;
    
    int f[maxn],mu[maxn],pri[maxn],vis[maxn],tot,p[maxn],s[maxn];
    
    void sieve() {
    	f[1]=mu[1]=1;
    	for(int i=2;i<maxn;i++) {
    		if(!vis[i]) pri[++tot]=i,mu[i]=-1,f[i]=i+1,p[i]=i,s[i]=i+1;
    		for(int t,j=1;j<=tot&&i*pri[j]<maxn;j++) {
    			vis[t=i*pri[j]]=1;
    			if(i%pri[j]==0) {
    				mu[t]=0;p[t]=p[i]*pri[j],s[t]=s[i]+p[t];
    				f[t]=f[i]/s[i]*s[t];break;
    			}
    			s[t]=pri[j]+1,f[t]=f[i]*s[t],p[t]=pri[j],mu[t]=-mu[i];
    		}
    	}
    	//for(int i=1;i<=10;i++) printf("%d %d %d %d
    ",i,f[i],s[i],p[i]);;
    }
    
    struct Binary_Indexed_Tree {
    	int tr[maxn];
    	void add(int x,int v) {for(int i=x;i<maxn;i+=i&-i) tr[i]+=v;}
    	int query(int x,int ans=0) {for(int i=x;i;i-=i&-i) ans+=tr[i];return ans;}
    }BIT;
    
    int solve(int n,int m) {
    	int T=1,ans=0;
    	while(T<=n) {
    		int pre=T;T=min(n/(n/T),m/(m/T));
    		ans+=(n/T)*(m/T)*(BIT.query(T)-BIT.query(pre-1));T++;
    	}return ans;
    }
    
    int n;
    struct input {
    	int n,m,a,id;
    	int operator < (const input &rhs ) const {return a<rhs.a;}
    }in[maxn],ans[maxn];
    
    struct Pair {
    	int first,second;
    	int operator < (const Pair &rhs ) const {return first<rhs.first;}
    }g[maxn];
    
    int cmp(input a,input b) {return a.id<b.id;}
    
    signed main() {
    	sieve();read(n);
    	for(int i=1;i<=n;i++) read(in[i].n),read(in[i].m),read(in[i].a),in[i].id=i;
    	sort(in+1,in+n+1);for(int i=1;i<maxn;i++) g[i].first=f[i],g[i].second=i;
    	sort(g+1,g+maxn);int now=0;
    	for(int i=1;i<=n;i++) {
    		while(g[now+1].first<=in[i].a&&now+1<maxn) {
    			now++;
    			for(int i=g[now].second;i<maxn;i+=g[now].second)
    				BIT.add(i,g[now].first*mu[i/g[now].second]);
    		}
    		if(in[i].n>in[i].m) swap(in[i].n,in[i].m);
    		ans[i].a=solve(in[i].n,in[i].m),ans[i].id=in[i].id;
    	}
    	sort(ans+1,ans+n+1,cmp);
    	for(int i=1;i<=n;i++) write(ans[i].a&((1u<<31)-1));
    	return 0;
    }
    
  • 相关阅读:
    POJ3320 Jessica's Reading Problem
    POJ3320 Jessica's Reading Problem
    CodeForces 813B The Golden Age
    CodeForces 813B The Golden Age
    An impassioned circulation of affection CodeForces
    An impassioned circulation of affection CodeForces
    Codeforces Round #444 (Div. 2) B. Cubes for Masha
    2013=7=21 进制转换
    2013=7=15
    2013=7=14
  • 原文地址:https://www.cnblogs.com/hbyer/p/10060688.html
Copyright © 2011-2022 走看看