浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ3561: DZY Loves Math VI

Description

给定正整数n,m。求

img

Input

一行两个整数n,m。

Output

一个整数,为答案模1000000007后的值。

Sample Input

5 4

Sample Output

424

HINT

数据规模:

1<=n,m<=500000,共有3组数据。

Source

By Jcvb

Solution

\[\begin{aligned} 原式=&\sum_{d=1}^nd^d\sum_{k=1}^{\frac{n}{d}}k^{2d}\mu(k)\sum_{i=1}^{\frac{n}{kd}}i^d\sum_{j=1}^{\frac{m}{kd}}j^d \end{aligned} \]

实际上就不用继续化简了,只需要可以均摊O(1)求出后面那个就行了。这样总复杂度就是\(O(nlogn)\)的。

考虑对于每个d,因为上界是\(\frac{n}{kd}\),所以根据调和级数算一下枚举均摊是\(O(nlogn)\)的,所以暴力算出来就好了。

Dzy Loves Math和这题比不知道高到哪去了

#include <bits/stdc++.h>
using namespace std;

#define mod 1000000007
#define N 500010
#define ll long long
ll sum[N], c[N], ans = 0;
int cnt, n, p[N], vis[N], mu[N], m;

void init(int n) {
	mu[1] = 1;
	for(int i = 2; i <= n; ++i) {
		if(!vis[i]) p[++cnt] = i, mu[i] = -1;
		for(int j = 1; j <= cnt && i * p[j] <= n; ++j) {
			vis[i * p[j]] = 1;
			if(i % p[j] == 0) break;
			mu[i * p[j]] = -mu[i];
		}
	}
}

ll power(ll a, ll b) { ll ans = 1;
	while(b) {
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod; b >>= 1;
	}
	return ans;
}

int main() {
	scanf("%d%d", &n, &m);
	if(n > m) swap(n, m);
	init(m);
	for(int i = 1; i <= m; ++i) c[i] = 1ll;
	for(int d = 1; d <= n; ++d) {
		for(int j = 1; j <= m / d; ++j) {
			c[j] = 1ll * c[j] * j % mod;
			sum[j] = sum[j - 1] + c[j];
			sum[j] %= mod;
		}
		ll s = 0;
		for(int i = 1; i <= n / d; ++i) {
			s = (s + (c[i] * c[i] % mod * mu[i] * sum[n/d/i] % mod * sum[m/d/i]) % mod) % mod;
		}
		ans = (ans + s * power(d, d)) % mod;
	}
	printf("%lld\n", (ans%mod+mod)%mod);
	return 0;
}
posted @ 2019-03-16 16:17  henry_y  阅读(179)  评论(0编辑  收藏  举报