• P3312 [SDOI2014]数表 题解


    P3312 [SDOI2014]数表

    推式子的时候默认 (n < m)

    (sigma(i)) 表示 (i) 的约数和

    [ ans= sumlimits _{i=1}^nsumlimits_{j=1}^{n} sigma(gcd(i,j))\ =sumlimits_{d=1}^{n} sum limits_{i=1}^{frac{n}{d}} sum limits_{j=1}^{frac{m}{d}} sigma(d)[gcd(i,j)==1]\ =sumlimits_{d=1}^{n} sum limits_{i=1}^{frac{n}{d}} sum limits_{j=1}^{frac{m}{d}} sumlimits_{x|d}mu(x) sigma(d)\ =sumlimits_{d=1}^{n} sigma(d) sum limits_{i=1}^{frac{n}{d}} sum limits_{j=1}^{frac{m}{d}} sumlimits_{x|d}mu(x)\ =sumlimits_{d=1}^{n} sigma(d) sumlimits_{x=1}^{frac{n}{d}}mu(x) dfrac{n}{dx} dfrac{m}{dx}\ sumlimits_{d=1}^n sigma(d) sumlimits_{T=1}^{n} mu(dfrac{T}{d})dfrac{n}{T} dfrac{m}{T}(T=dx)\ =sumlimits_{T=1}^{n}dfrac{n}{T} dfrac{m}{T}sumlimits_{d|T}sigma(d)mu(dfrac{T}{d})\ ]

    先线性筛出 (mu)(sigma) 可以 (O(nlog n)) 暴力算,前面套个整除分块即可。

    但是加上 (a) 的限制之后。。。

    发现只有 (sigma(i)le a) 的时候才可以对于那个 (T) 产生贡献。

    所以考虑离线询问,将 (a) 从小到大排序,还要预处理所有的 (sigma(i)) 从小到大排序,用树状数组暴力修改即可。

    附赠一组较强样数据供调试

    Input
    1
    25291 26958 42646
    Output
    235628669
    
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef double db;
    #define pb(x) push_back(x)
    #define mkp(x,y) make_pair(x,y)
    //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    //char buf[1<<21],*p1=buf,*p2=buf;
    #define int long long
    inline unsigned read() {
    	unsigned x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    	return x*f;
    }
    const int N = 20005;
    const int M = 100005;
    const int mod = 1ll << 31;
    int ans[N], tr[M];
    bool vis[M];
    int mu[M], pri[M], cnt, q, it = 1;
    struct node {
    	int n, m, a, id;
    	inline bool operator<(const node&rhs)const{return a < rhs.a;}
    }a[N];
    struct fact {
    	int id, x;
    	inline bool operator<(const fact&rhs)const{return x < rhs.x;}
    }f[M];
    void add(int x, int d) {
    	for (int i = x; i < M; i += i & -i) tr[i] += d;
    }
    int ask(int x) {
    	int res = 0;
    	for (int i = x; i > 0; i -= i & -i) res += tr[i];
    	return res;
    }
    void Sieve() {
    	mu[1] = 1;
    	for (int i = 2; i < M; ++ i) {
    		if (! vis[i]) pri[++ cnt] = i, mu[i] = -1;
    		for (int j = 1; i * pri[j] < M; ++ j) {
    			vis[i * pri[j]] = 1;
    			if(i % pri[j] == 0) break;
    			mu[i * pri[j]] = - mu[i];
    		}
    	}
    	for (int i = 1; i < M; ++ i) 
    		for (int j = 1; i * j < M; ++ j)
    			f[i * j].x += i;
    	for(int i = 1; i < M; ++ i) f[i].id = i;
    	sort(f + 1, f + M);
    }
    signed main() {
    	Sieve();
    	q = read();
    	for (int i = 1; i <= q; ++ i)
    		a[i].n = read(), a[i].m = read(), a[i].a = read(), a[i].id = i;
    	sort(a + 1, a + q + 1);
    	for (int i = 1; i <= q; ++ i) {
    		while (it < M && f[it].x <= a[i].a) {
    			int t = f[it].id;
    			for (int j = 1; j * t < M; ++ j) add(j * t, f[it].x * mu[j]);
    			++ it;
    		} 
    		int res = 0, n = a[i].n, m = a[i].m;
    		if (n > m) swap(n, m);
    		for (int l = 1, r; l <= n; l = r + 1)
    			r = min(n / (n / l), m / (m / l)), res += (n / l) * (m / l) * (ask(r) - ask(l - 1));
    		ans[a[i].id] = res;
    	}
    	for (int i = 1; i <= q; ++ i) printf("%lld
    ", ans[i] % mod);
    	return 0;
    }
    
    路漫漫其修远兮,吾将上下而求索
  • 相关阅读:
    BZOJ 3218: a + b Problem
    P4542 [ZJOI2011]营救皮卡丘
    P4843 清理雪道
    P4553 80人环游世界
    P4126 [AHOI2009]最小割
    P2619 [国家集训队2]Tree I
    P2469 [SDOI2010]星际竞速
    P2050 [NOI2012]美食节
    易语言入门
    jdbc连接oracle语法
  • 原文地址:https://www.cnblogs.com/zzctommy/p/13727080.html
Copyright © 2020-2023  润新知