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

    题目链接

    solution

    “能同时整除i和j的数”其实就是(gcd(i,j))的因数。

    所以题目就是要求

    [sumlimits_{g=1,sigma(g)le a}sigma(g)sumlimits_{i=1}^{lfloorfrac{n}{g} floor}sumlimits_{j=1}^{lfloorfrac{m}{g} floor}[gcd(i,j)=1] ]

    [=sumlimits_{g=1,sigma(g)le a}sigma(g)sumlimits_{d=1}^{lfloorfrac{n}{g} floor}mu(d)lfloorfrac{n}{dg} floorlfloorfrac{m}{dg} floor ]

    (T=gd)

    [=sumlimits_{T=1}^nlfloorfrac{n}{T} floorlfloorfrac{m}{T} floorsumlimits_{g|T,sigma(g)le a}sigma(g)mu(frac{T}{g}) ]

    (f(i)=sumlimits_{d|i}sigma(d)mu(frac{i}{d}))

    后面这部分只有当(sigma(g)le a)时才会产生贡献,如果没有(sigma(g)le a)这个限制的话,我们可以直接先预处理(f)(枚举(g),再枚举(g)的倍数即可),然后前缀和数论分块,搞定。

    然后考虑如何处理这个限制,我们可以把询问离线下来,然后按照(a)排序,将(sigma(g))也按照大小排序,从小到大的处理询问,当当前的(g)可以产生贡献时,就更新(f(kg))

    然后还要维护前缀和,所以再用个树状数组维护即可。

    复杂度(O(nlog^2n+Qsqrt{n}logn))

    code

    /*
    * @Author: wxyww
    * @Date:   2020-04-23 10:59:26
    * @Last Modified time: 2020-04-23 11:39:46
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef unsigned int Uint;
    const int N = 100010;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1; c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0'; c = getchar();
    	}
    	return x * f;
    }
    ll o[N];
    
    int ans[N],vis[N],prime[N];
    Uint mu[N];
    struct node {
    	int n,m,x,id;
    }a[N];
    #define pi pair<ll,int>
    
    pi t[N];
    
    bool cmp(const node &A,const node &B) {
    	return A.x < B.x;
    }
    
    void pre() {
    	for(int i = 1;i <= 100000;++i)
    		for(int j = i;j <= 100000;j += i)
    			o[j] += i;
    	
    	for(int i = 1;i <= 100000;++i)
    		t[i] = make_pair(o[i],i);
    	
    	mu[1] = 1;
    	int tot = 0;
    	for(int i = 2;i <= 100000;++i) {
    		if(!vis[i]) {
    			prime[++tot] = i;
    			mu[i] = -1;
    		}
    		for(int j = 1;j <= tot && prime[j] * i <= 100000;++j) {
    			vis[prime[j] * i] = 1;
    			if(i % prime[j]) mu[i * prime[j]] = -mu[i];
    			else break;
    	
    		}
    	}
    
    }
    Uint tree[N];
    void update(int pos,Uint c) {
    
    	while(pos <= 100000) {
    		tree[pos] += c;
    		pos += pos & -pos;
    	}
    }
    Uint query(int pos) {
    	Uint ret = 0;
    	while(pos) {
    		ret += tree[pos];
    		pos -= pos & -pos;
    	}
    	return ret;
    }
    int main() {
    	int Q = read();
    	for(int i = 1;i <= Q;++i) {
    		a[i].n = read(),a[i].m = read();a[i].x = read();
    		a[i].id = i;
    	}
    	
    	pre();
    	sort(a + 1,a + Q + 1,cmp);
    	sort(t + 1,t + 100001);
    
    	int p = 1;
    	for(int i = 1;i <= Q;++i) {
    
    		while(p <= 100000 && t[p].first <= a[i].x) {
    			for(int j = t[p].second;j <= 100000;j += t[p].second) {
    				update(j,(Uint)t[p].first * mu[j / t[p].second]);
    			}
    			++p;
    		}
    
    		int n = a[i].n,m = a[i].m;
    		if(n > m) swap(n,m);
    		Uint ret = 0;
    
    		for(int l = 1,r;l <= n;l = r + 1) {
    			r = min(n / (n / l),m / (m / l));
    			ret += (Uint) (n / l) * (m / l) * (query(r) - query(l - 1));
    		}
    		ans[a[i].id] = ret;
    
    	}
    
    	for(int i = 1;i <= Q;++i) cout<<(ans[i] & ((1ll << 31) - 1))<<endl;
    	return 0;
    }
    
  • 相关阅读:
    rocketmq学习(一) rocketmq介绍与安装
    基于redis的分布式锁实现
    SSTI(服务器模板注入)学习
    PHP文件包含漏洞(利用phpinfo)复现
    ubuntu搭建vulhub漏洞环境
    sqli-labs通关教程----51~65关
    sqli-labs通关教程----41~50关
    sqli-labs通关教程----31~40关
    sqli-labs通关教程----21~30关
    sqli-labs通关教程----11~20关
  • 原文地址:https://www.cnblogs.com/wxyww/p/bzoj3529.html
Copyright © 2011-2022 走看看