• Bzoj3529: [Sdoi2014]数表


    题面

    传送门

    Sol

    先不管(a)的限制
    (f(n))表示f的约数和((据说是sigma)),它是个积性函数(筛法)(n<m)

    则题目要求的就是(sum_{i=1}^{n}sum_{j=1}^{m}f(gcd(i, j)))

    考虑每个(gcd)的贡献,(sum_{i=1}^{n}f(i)sum_{j=1}^{lfloorfrac{n}{i} floor}mu(j)lfloorfrac{n}{i*j} floorlfloorfrac{m}{i*j} floor)

    替换(i*j)就是(sum_{k=1}^{n}lfloorfrac{n}{k} floorlfloorfrac{m}{k} floorsum_{d|k}f(d)mu(frac{k}{d}))

    但是我们有限制,就不能直接筛(sum_{d|k}f(d)mu(frac{k}{d}))

    所以考虑离线处理,把询问按a排序,每次把小于等于a的(f)同它的所有倍数n的(sum_{d|n}f(d)mu(frac{n}{d}))加进来,树状数组维护前缀和即可

    只要预处理处(mu)(f)就好了,见上面的筛法链接

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(1e5 + 1), INF(2147483647);
    
    IL ll Read(){
        RG ll x = 0, z = 1; RG char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    int prime[_], num, N, Q, id[_], ans[_], f[_], mu[_], sumd[_], powd[_], bit[_];
    bool isprime[_];
    struct Qry{
    	int n, m, a, id;
    	IL bool operator <(RG Qry B) const{  return a < B.a;  }
    } qry[_];
    
    IL void Prepare(){
    	isprime[1] = 1; id[1] = f[1] = mu[1] = 1;
    	for(RG int i = 2; i < N; ++i){
    		id[i] = i;
    		if(!isprime[i]){
    			prime[++num] = i; f[i] = i + 1; mu[i] = -1;
    			sumd[i] = 1 + i; powd[i] = i;
    		}
    		for(RG int j = 1; j <= num && i * prime[j] < N; ++j){
    			isprime[i * prime[j]] = 1;
    			if(i % prime[j]){
    				sumd[i * prime[j]] = 1 + prime[j]; powd[i * prime[j]] = prime[j];
    				f[i * prime[j]] = f[i] * f[prime[j]];
    				mu[i * prime[j]] = -mu[i];
    			}
    			else{
    				mu[i * prime[j]] = 0;
    				powd[i * prime[j]] = powd[i] * prime[j];
    				sumd[i * prime[j]] = sumd[i] + powd[i * prime[j]];
    				f[i * prime[j]] = f[i] / sumd[i] * sumd[i * prime[j]];
    				break;
    			}
    		}
    	}
    }
    
    IL bool Cmp(RG int x, RG int y){  return f[x] < f[y];  }
    
    IL void Add(RG int x, RG int d){  for(; x < N; x += x & -x) bit[x] += d;  }
    
    IL int Query(RG int x){  RG int ret = 0; for(; x; x -= x & -x) ret += bit[x]; return ret;  }
    
    IL int Calc(RG int n, RG int m){
    	RG int ret = 0, lst = 0, now;
    	for(RG int i = 1, j; i <= n; i = j + 1){
    		j = min(n / (n / i), m / (m / i));
    		now = Query(j);
    		ret += (n / i) * (m / i) * (now - lst);
    		lst = now;
    	}
    	return ret;
    }
    
    int main(RG int argc, RG char* argv[]){
    	Q = Read();
    	for(RG int i = 1, n, m, a; i <= Q; ++i){
    		n = Read(); m = Read(); a = Read();
    		if(n > m) swap(n, m);
    		qry[i] = (Qry){n, m, a, i};
    		N = max(N, n + 1);
    	}
    	Prepare();
    	sort(qry + 1, qry + Q + 1); sort(id + 1, id + N, Cmp);
    	for(RG int i = 1, j = 1; i <= Q; ++i){
    		for(; j < N && f[id[j]] <= qry[i].a; ++j)
    			for(RG int k = id[j]; k < N; k += id[j])
    				Add(k, f[id[j]] * mu[k / id[j]]);
    		ans[qry[i].id] = Calc(qry[i].n, qry[i].m);
    	}
    	for(RG int i = 1; i <= Q; ++i) printf("%d
    ", ans[i] < 0 ? ans[i] + INF + 1 : ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    git提交本地代码到远程服务器
    报错 D:Program Files odejs ode_cache\_logs2019-05-07T07_07_30_992Z-debug.log
    vue项目中使用插件将字符串装化为格式化的json数据(可伸缩)
    odoo官方文档第二章 Data Files
    odoo官方文档第一章 ORM
    odoo模块的创建 openacademy学习笔记
    mysql存储过程的学习(二)
    mysql存储过程的学习(一)
    linux 进入mysql的常用命令(转)
    Dubbo入门学习(转)
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8301699.html
Copyright © 2020-2023  润新知