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

    题意

    3529: [Sdoi2014]数表

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 3009  Solved: 1559
    [Submit][Status][Discuss]

    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

    HINT

    Source

    [Submit][Status][Discuss]
    
    HOME Back

    分析

    参照MashiroSky的题解。

    题意

    多组询问,每次给出({n,m,a})。求$${sum_{i=1}^nsum_{j=1}^m[sum_{d|i,d|j}d<=a]sum_{d|i,d|j}d}$$

    Solution

    ({a})的限制很不好做,我们不妨先来看看如果没有({a})的限制,是个什么情况。

    [egin{aligned} & sum_{i=1}^nsum_{j=1}^msum_{d|i,d|j}d \ =&sum_{i=1}^nsum_{j=1}^msum_{d=1}^{min(n,m)}f(d)[gcd(i,j)=d] end{aligned} ]

    这里({f(d)})表示({d})的约数和,由约数和定理:$${d=p_1^{a_1}p_2^{a_2}p_3^{a_3}······p_k^{a_k}}$$

    [{f(d)=(p_1^0+p_1^1+······+p_1^{a_1})(p_2^0+p_2^1+······+p_2^{a_2})······(p_k^0+p_k^1+······+p_k^{a_k})} ]

    我们发现当({p,q})互质时,({f(pq)=f(p)f(q)})({f})是个积性函数。也就是说({f})可以线性筛求解,具体求法可以看代码。回到上面的问题,我们继续变化这个式子。

    [egin{aligned} &sum_{i=1}^nsum_{j=1}^msum_{d=1}^{min(n,m)}f(d)[gcd(i,j)=d] \ =&sum_{d=1}^{min(n,m)}f(d)sum_{i=1}^{lfloor{n/d} floor}sum_{j=1}^{lfloor{m/d} floor}[gcd(i,j)=1] \ =&sum_{d=1}^{min(n,m)}f(d)sum_{t=1}^{min(lfloor{n/d} floor,lfloor{m/d} floor)}μ(t)lfloorfrac{n}{dt} floorlfloorfrac{m}{dt} floor end{aligned} ]

    我们令({Q=dt}),先枚举({Q}),得到:$${sum_{Q=1}^{min(n,m)}lfloorfrac{n}{Q} floorlfloorfrac{m}{Q} floorsum_{d|Q}f(d)μ(frac{Q}{d})}$$

    我们对({f})({μ})函数的狄利克雷卷积({g(Q)=sum_{d|Q}f(d)μ(frac{Q}{d})})预处理前缀和,前面的({lfloorfrac{n}{Q} floorlfloorfrac{m}{Q} floor})分块,那么这个式子的计算就达到了({sqrt{n}})

    考虑如何加入限制({a})

    我们可以离线,将询问按照({a})从小到大排序,({f})函数按照从小到大排序。询问的时候,我们就动态维护一个树状数组({c})。树状数组的每一位({c[x]})存的是卷积({g(x)})({f(d)})不超过({a})的数之和。数据组数为({T}),询问复杂度({O(Tsqrt{n}logn)})

    细节

    这题复杂度有点卡,对于取模运算我们可以对({int})自然溢,最后再({&2147483647})就可以了。

    代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;
        rg char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-') w=-1;
            ch=getchar();
        }
        while(isdigit(ch))
            data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x){
        return x=read<T>();
    }
    typedef long long ll;
    
    co int maxn=1e5+1,INF=0x7fffffff;
    int mu[maxn],ans[maxn],c[maxn],p[maxn],t[maxn],g[maxn];
    struct F{int d,num;}f[maxn];
    struct Q{int n,m,a,id;}q[maxn];
    bool cmpT(co Q&a,co Q&b) {return a.a<b.a;}
    bool cmpt(co F&a,co F&b) {return a.d<b.d;}
    #define lowbit(x) (x&-x)
    int power(int a,int b){
    	int res=1;
    	while(b){
    		if(b&1) res*=a;
    		a*=a,b>>=1;
    	}
    	return res;
    }
    void add(int x,int val){
    	for(int i=x;i<maxn;i+=lowbit(i)) c[i]+=val;
    }
    int query(int x){
    	int s=0;
    	for(int i=x;i>=1;i-=lowbit(i)) s+=c[i];
    	return s;
    }
    int main(){
    //	freopen(".in","r",stdin),freopen(".out","w",stdout);
    	mu[1]=1,f[1].d=f[1].num=1;
    	for(int i=2;i<maxn;++i){
    		f[i].num=i;
    		if(!p[i]) mu[i]=-1,f[i].d=t[i]=1+i,g[i]=1,p[++p[0]]=i;
    		for(int j=1;j<=p[0]&&i*p[j]<maxn;++j){
    			p[i*p[j]]=1;
    			if(i%p[j]==0){
    				mu[i*p[j]]=0;
    				g[i*p[j]]=g[i]+1;
    				t[i*p[j]]=t[i]+power(p[j],g[i]+1);
    				f[i*p[j]].d=f[i].d/t[i]*t[i*p[j]];
    			}
    			else{
    				mu[i*p[j]]=-mu[i];
    				f[i*p[j]].d=f[i].d*f[p[j]].d;
    				g[i*p[j]]=1;t[i*p[j]]=p[j]+1;
    			}
    		}
    	}
    	int T=read<int>();
    	for(int i=1;i<=T;++i) read(q[i].n),read(q[i].m),read(q[i].a),q[i].id=i;
    	std::sort(q+1,q+T+1,cmpT);
    	std::sort(f+1,f+maxn,cmpt);
    	for(int now=0,i=1;i<=T;++i){
    		while(now+1<maxn&&f[now+1].d<=q[i].a){
    			++now;
    			for(int j=1;j*f[now].num<maxn;++j)
    				add(j*f[now].num,mu[j]*f[now].d);
    		}
    		int n=q[i].n,m=q[i].m;
    		if(n>m) std::swap(n,m);
    		for(int j=1,k;j<=n;j=k+1){
    			k=std::min(n/(n/j),m/(m/j));
    			ans[q[i].id]+=(n/j)*(m/j)*(query(k)-query(j-1));
    		}
    		ans[q[i].id]&=INF;
    	}
    	for(int i=1;i<=T;++i) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Binder核心原理解析
    写给 Android 应用工程师的 Binder 原理剖析
    Android Binder原理解析
    Android面试题(25)-Bundle机制_pgg_cold的博客-CSDN博客_android bundle机制
    腾讯Android面试精选题——谈一谈Binder的原理和实现一次拷贝的流程
    把这份关于Android Binder原理一系列笔记研究完,进大厂是个“加分项”...
    大型项目必备IPC之其他IPC方式(二)
    骚年!用Binder原理去彻底征服Android大厂面试官吧
    还不懂Binder的原理?那么你即将损失一张腾讯的offer
    每日一问 Binder
  • 原文地址:https://www.cnblogs.com/autoint/p/10484937.html
Copyright © 2011-2022 走看看