P2522 HAOI2011
題意
對於給出的n個詢問,每次求有多少個數對,滿足,,且,函數爲和的最大公約數.
題解
即求式子.
記
根據二維前綴和公式,可以將式子轉換成:
因此我們只要能得到的計算方法即可.
求的套路非常明顯:莫比比烏斯反演
由於.
反演得到
令.
對上式子進行分塊計算,可以將時間複雜度從降至.
總結
對於形如這樣的式子,我們都可以用代換後數論分塊進行加速.
時間複雜度從降至.
代碼
#include <iostream>
#include <algorithm>
#include <cstring>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)
const int N = 50000;
int prime[N+10],zhi[N+10],mu[N+10],pcnt;
void sieve() {
zhi[1] = mu[1] = 1;
for(int i = 2;i <= N;++i) {
if(!zhi[i]) {
mu[i] = -1;
prime[pcnt++] = i;
}
for(int j = 0;j < pcnt && prime[j]*i <= N;++j) {
zhi[i*prime[j]] = 1;
if(i % prime[j] == 0) {
mu[i*prime[j]] = 0;
break;
}
else
mu[i*prime[j]] = -mu[i];
}
}
for(int i = 1;i <= N;++i) mu[i] += mu[i-1];
}
int a,b,c,d,k,T;
int calc(int n,int m) {
int ans = 0;
int lim = std::min(n/k,m/k);
for(int i = 1,nx1,nx2,nxt;i <= lim;i=nxt+1) {
nx1 = n/(n/i);
nx2 = m/(m/i);
nxt = nx1>nx2?nx2:nx1;
ans += (mu[nxt]-mu[i-1])*(n/i/k)*(m/i/k);
}
return ans;
}
int main() {
std::ios::sync_with_stdio(false);
sieve();
std::cin >> T;
while(T--) {
std::cin >> a >> b >> c >> d >> k;
int ans = calc(b,d)+calc(a-1,c-1)-calc(a-1,d)-calc(b,c-1);
std::cout << ans << std::endl;
}
return 0;
}