zoukankan      html  css  js  c++  java
  • 【SDOI2014】数表

    题面

    题解

    不管$a$的限制

    我们要求的东西是:($sigma(x)$是$x$的约数个数和)

    $ sum_{i=1}^nsum_{j=1}^msigma(gcd(i,j)) $

    设$f(x)=sigma(x)$,则我们可以找到一个$g$使得$f=1*g$,那么$g=mu*f$

    所以$g(x)=sum_{d|x}mu(d)sigma(frac xd)$

    带入原式得:

    $ sum_{i=1}^nsum_{j=1}^msigma(gcd(i,j)) \ =sum_{d=1}^n g(d)leftlfloorfrac nd ight floor leftlfloorfrac md ight floor \ =sum_{d=1}^n leftlfloorfrac nd ight floor leftlfloorfrac md ight floor sum_{x|d}mu(x)sigma(frac dx) $

    我们可以筛出$g(x)$的值来$O(sqrt n)$回答

    但是现在有$a$的限制,就可以离线将询问排序,将$sigma$排序,加入相对应的位置就可以了。

    代码

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<climits>
    #include<algorithm>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
    #define clear(x, y) memset(x, y, sizeof(x))
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while(ch != '-' && (!isdigit(ch))) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int maxn(100010);
    bool not_prime[maxn];
    int prime[maxn], cnt, n, T, ans[maxn];
    int mu[maxn], sig[maxn], sumd[maxn], powd[maxn];
    
    struct qry { int n, m, a, id; } q[maxn];
    int p[maxn], c[maxn];
    inline bool operator < (const qry &a, const qry &b) { return a.a < b.a; }
    
    void init(int N)
    {
    	not_prime[1] = true; sig[1] = mu[1] = p[1] = 1;
    	for(RG int i = 2; i <= N; i++)
    	{
    		p[i] = i;
    		if(!not_prime[i]) prime[++cnt] = i, mu[i] = -1,
    			sig[i] = i + 1, sumd[i] = i + 1, powd[i] = i;
    		for(RG int j = 1; j <= cnt && i * prime[j] <= N; j++)
    		{
    			not_prime[i * prime[j]] = true;
    			if(i % prime[j])
    			{
    				mu[i * prime[j]] = -mu[i];
    				sig[i * prime[j]] = sig[i] * sig[prime[j]];
    				sumd[i * prime[j]] = prime[j] + 1;
    				powd[i * prime[j]] = prime[j];
    			}
    			else
    			{
    				powd[i * prime[j]] = powd[i] * prime[j];
    				sumd[i * prime[j]] = sumd[i] + powd[i * prime[j]];
    				sig[i * prime[j]] = sig[i] / sumd[i] * sumd[i * prime[j]];
    				break;
    			}
    		}
    	}
    }
    
    inline bool cmp(int a, int b) { return sig[a] < sig[b]; }
    void add(int x, int v) { while(x <= n) c[x] += v, x += x & -x; }
    int query(int x) { int ans = 0; while(x) ans += c[x], x -= x & -x; return ans; }
    int solve(int x, int y)
    {
    	int now = 0, pre = 0, ans = 0;
    	for(RG int i = 1, j; i <= x; i = j + 1)
    	{
    		j = std::min(x / (x / i), y / (y / i));
    		now = query(j); ans += (x / i) * (y / i) * (now - pre);
    		pre = now;
    	}
    	return ans;
    }
    
    int main()
    {
    	T = read();
    	for(RG int i = 1; i <= T; i++)
    	{
    		q[i] = (qry) {read(), read(), read(), i};
    		if(q[i].n > q[i].m) std::swap(q[i].n, q[i].m);
    		n = std::max(n, q[i].n);
    	}
    	init(n); std::sort(q + 1, q + T + 1);
    	std::sort(p + 1, p + n + 1, cmp);
    	for(RG int i = 1, j = 1; i <= T; i++)
    	{
    		for(; j <= n && sig[p[j]] <= q[i].a; ++j)
    			for(RG int k = p[j]; k <= n; k += p[j])
    				if(mu[k / p[j]]) add(k, sig[p[j]] * mu[k / p[j]]);
    		ans[q[i].id] = solve(q[i].n, q[i].m);
    	}
    	for(RG int i = 1; i <= T; i++)
    	{
    		if(ans[i] < 0) ans[i] += INT_MAX, ++ans[i];
    		printf("%d
    ", ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    接口测试基础知识
    WebSocket接口怎么做测试
    python的数据类型特点和常用方法
    python封装一个工具类 ,对MySQL数据库增删改查
    python 往MySQL批量插入数据
    python对MySQL进行曾删改查
    Rest Assured从入门到遇到各种问题(汇总、更新)
    jmeter参数化之动态读取csv文件
    Charles 浏览器(火狐)抓包设置
    导入git项目报错"no projects are found to import" 找不到项目
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10177581.html
Copyright © 2011-2022 走看看