[SDOI2014]数表

题面就懒得放了,给个链接:LOJ
自己的想法:

[egin{aligned} &sum_{i=1}^nsum_{j=1}^msigma(gcd(i.j))\ &=sum_{i=1}^nsum_{j=1}^msum_{x|(i,j)}x\ &=sum_{x=1}^nsum_{i=1}^{frac{n}{x}}sum_{j=1}^frac{m}{x} end{aligned} ]

然后就gg了,无法处理 (le a) 的限制。
下面是正解(by Wolfycz):
2019-09-11 21-14-36 的屏幕截图.png

(sigma(P) = P +1)
(aperp b,)

[egin{aligned} sigma(ab)&=sum_{x|ab}x\ &=sum_{x|a}sum_{y|b}xy\ &=sigma(a)sigma(b) end{aligned} ]

(a)包含(p)这个质因子

[sigma(pa) = sigma(a) + sigma(frac{a}{low(a)})low(ap) ]

其中 (low(x))(x) 最小质因子的指数次幂,若 (x = prod p_i^{c_i},p_1<p_2cdots) ,则 (low(x) = p_1^{c_1})
然后就可以欧拉筛了。

(sigma) 筛出来后,注意到 (sum_{d|T}sigma(d)mu(frac{T}{d})) 只有 (sigma(d)le a) 才会有贡献,所以我们把询问按 (a) 从小到大排序,然后把 (sigma(d) le a)(sigma(d)mu(frac{T}{d})) 插入树状数组,枚举 (d) 的倍数,就可以做到 (O(nln nlog n))

查询就数论分块+树状数组区间求和 (O(qsqrt n log_2n)。)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <fstream>

#define uint unsigned int
typedef long long LL;
typedef unsigned long long uLL;

#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define GO cerr << "GO" << endl;

using namespace std;

inline void proc_status()
{
	ifstream t("/proc/self/status");
	cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
}

template<class T> inline T read() 
{
	register T x(0);
	register char c;
	register int f(1);
	while (!isdigit(c = getchar())) if (c == '-') f = -1;
	while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
	return x * f;
}

template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }

const int maxN = 1e5;

struct Query
{
	uint n, m, id;
	uint ans;
	unsigned int a;
} q[maxN + 2];

struct BIT
{
	unsigned int t[maxN + 2];
	void add(int x, unsigned int y) { for (; x <= maxN; x += x & -x) t[x] += y; }
	unsigned int query(int x) 
	{
		unsigned int ans = 0;
		for (; x; x -= x & -x)
			ans += t[x];
		return ans;
	}
} T;

int Q;
bool vis[maxN + 2];
vector<unsigned int> prime;
pair<unsigned int, unsigned int> sigma[maxN + 2];
unsigned int mu[maxN + 2], low[maxN + 2];

void Input()
{
	Q = read<int>();
	for (int i = 1; i <= Q; ++i) 
		q[i].n = read<int>(), q[i].m = read<int>(), q[i].a = read<int>(), q[i].id = i;
}

void Init()
{
	sigma[1] = MP(1, 1);
	mu[1] = 1;
	for (register int i = 2; i <= maxN; ++i)
	{
		if (!vis[i])
		{
			mu[i] = -1;
			low[i] = i;
			sigma[i] = MP(1 + i, i);
			prime.push_back(i);
		}
		for (register int j = 0; j < SZ(prime) && prime[j] * i <= maxN; ++j)
		{
			int t = prime[j] * i;
			vis[t] = 1;
			if (i % prime[j] == 0)
			{
				low[t] = low[i] * prime[j];
				mu[t] = 0;
				sigma[t] = MP(sigma[i].first + low[t] * sigma[i / low[i]].first, t);
			}
			else
			{
				low[t] = prime[j];
				mu[t] = -mu[i];
				sigma[t] = MP(sigma[i].first * sigma[prime[j]].first, t);
			}
		}
	}
	//DEBUG("%d
", sigma[9].first);
	sort(sigma + 1, sigma + 1 + maxN);
}

bool cmp(const Query& A, const Query& B) { return A.a < B.a; }
bool cmp2(const Query& A, const Query& B) { return A.id < B.id; }

void Solve()
{
	sort(q + 1, q + 1 + Q, cmp);
	int pos = 0;
	for (int i = 1; i <= Q; ++i)
	{
		while (sigma[pos + 1].first <= q[i].a and pos < maxN)
		{
			pos++;
			for (int j = 1; j * sigma[pos].second <= maxN; ++j)
				T.add(sigma[pos].second * j, sigma[pos].first * mu[j]);
		}
		unsigned int ans = 0;
		if (q[i].n > q[i].m) swap(q[i].n, q[i].m);
		int n = q[i].n, m = q[i].m;
		for (register int l = 1, r; l <= n; l = r + 1)
		{
			r = min(n / (n / l), m / (m / l));
			ans += (T.query(r) - T.query(l - 1)) * (n / l) * (m / l);
		}
		q[i].ans = ans & 0x7FFFFFFF;
	}
	sort(q + 1, q + 1 + Q, cmp2);
	for (int i = 1; i <= Q; ++i)
		printf("%d
", q[i].ans);
}

int main() 
{
#ifndef ONLINE_JUDGE
	freopen("xhc.in", "r", stdin);
	freopen("xhc.out", "w", stdout);
#endif
	Input();
	Init();
	Solve();
	return 0;
}
原文地址:https://www.cnblogs.com/cnyali-Tea/p/11509925.html