zoukankan      html  css  js  c++  java
  • P3312 [SDOI2014]数表(莫比乌斯反演+树状数组)

    题目描述:

    有一张(n imes m)的数表。

    其第(i)行第(j)列((1 leq i leq n,1 leq j leq m))的数值为能同时整除(i)(j)的所有自然数之和。

    给定(a),计算数表中不大于(a)的数之和。

    (d(x))(x)的因子之和。

    写出式子:

    (sum_{i=1}^nsum_{j=1}^md(gcd(i,j))(d(gcd(i,j))<=A))

    化简:

    (sum_{k=1}d(k)(d(k)<=A)sum_{i=1}^{n/k}sum_{j=1}^{m/k}[gcd(i,j)=1])

    然后套莫比乌斯函数性质:

    (sum_{k=1}^nd(k)(d(k)<=A)sum_{i=1}^{n/k}sum_{j=1}^{m/k}sum_{x|gcd(i,j)}mu(x))

    (sum_{k=1}^nd(k)(d(k)<=A)sum_{d=1}^{n/k}mu(x)[n/kd][m/kd])

    (T=kd),因为(d)和函数名称(d)重复,这里把参数(d)换成(x),有:

    (sum_{T=1}^n[n/T][m/T]sum_{x|T}mu(T/x)d(T/x))

    后面这个和(T,A)有关的函数,如果(A)是固定的,可以通过预处理出所有函数(d),然后只保存小于等于(A)的函数(d)值。

    处理出前缀和,询问的时候直接上板子即可。

    但是(A)是变化的,怎么办?

    考虑将询问离线,按(A)值从小到大排序。

    预处理(d(x))函数,按照函数值从小到大排序。

    然后随着(A)的变大,不断把新的符合条件的(d(x))插入到树状数组中。

    然后用莫比乌斯反演算的时候就是区间求和的过程。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+100;
    const long long mod=(1ll<<31);
    typedef long long ll;
    ll vis[maxn],pri[maxn],mu[maxn],sum[maxn],cnt;
    ll mm[maxn],mt[maxn],pm[maxn];
    int cmp (int x,int y) {
    	return mm[x]<mm[y];
    }
    void getMu (int n) {
    	mu[1]=1;
    	for (int i=2;i<=n;i++) {
    		if (!vis[i]) {
    			mu[i]=-1;
    			pri[++cnt]=i;
    		}
    		for (int j=1;j<=cnt&&i*pri[j]<=n;j++) {
    			vis[i*pri[j]]=1;
    			if (i%pri[j]==0) break;
    			else mu[i*pri[j]]=-mu[i];
    		}
    	}
    	for (int i=1;i<=n;i++) {
    		for (int j=i;j<=n;j+=i) {
    			mm[j]+=i;
    		}
    	}
    	for (int i=1;i<=n;i++) pm[i]=i;
    	sort(pm+1,pm+n+1,cmp);	
    }
    struct query {
    	int n,m,a,id;
    	bool operator < (const query &r) const {
    		return a<r.a;
    	}
    }qq[maxn];
    ll c[maxn];//树状数组
    int lowbit (int x) {
    	return x&-x;
    }
    void up (int p,int v) {
    	for (int i=p;i<=1e5;i+=lowbit(i)) c[i]+=v,c[i]%=mod;
    } 
    ll getsum (int p) {
    	ll ans=0;
    	for (int i=p;i;i-=lowbit(i)) ans=(ans+c[i])%mod;
    	return ans;
    }
    ll ans[maxn];
    main () {
    	getMu(1e5);
    	int q;
    	scanf("%d",&q);
    	for (int i=1;i<=q;i++) {
    		scanf("%d%d%d",&qq[i].n,&qq[i].m,&qq[i].a);
    		qq[i].id=i;
    	}
    	sort(qq+1,qq+q+1);
    	int tot=1;
    	int pre=0;
    	for (int i=1;i<=q;i++) {
    		while (tot<=1e5) {
    			if (mm[pm[tot]]<=qq[i].a) {
    				//up(pm[tot],mm[pm[tot]]);
    				for (int j=pm[tot];j<=1e5;j+=pm[tot]) {
    					up(j,1ll*mu[j/pm[tot]]*mm[pm[tot]]%mod);
    				}
    				tot++;
    			}
    			else {
    				break;
    			}
    		}
    		if (qq[i].n>qq[i].m) swap(qq[i].n,qq[i].m);
    		for (int l=1,r;l<=qq[i].n;l=r+1) {
    			r=min(qq[i].n/(qq[i].n/l),qq[i].m/(qq[i].m/l));
    			ans[qq[i].id]+=1ll*(qq[i].n/l)*(qq[i].m/l)%mod*(getsum(r)-getsum(l-1)+mod)%mod;
    			ans[qq[i].id]%=mod;
    		}
    	} 
    	for (int i=1;i<=q;i++) printf("%lld
    ",ans[i]);
    }
    
  • 相关阅读:
    Log4NET初接触
    wwwww
    关于ASP.NET 的进程帐户对 IIS 元数据库读访问权问题
    CentOS8 .NET Core项目部署
    CentOS7.6中安装Apache及Apache常见操作和配置说明
    .net core 命令行下启动指定端口
    Centos7安装mongodb
    centos8+oracle19开机自启动
    计算机网络常用端口
    Centos7安装mongodb
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/15004218.html
Copyright © 2011-2022 走看看