注意:
因为是多组询问(5000)而n又高达5e5,所以我们每次的时间一定要控制在logn或sqrt(n)内才能1s过,分块是必须的了。
然后是一个坑点:必须在线性筛里统计数量,自己写函数一个个统计会t在这上。
跟csu 1325的思路类似:需要预处理出
F(i)
的系数,然后求前缀和分块。然而这题p的值会影响某些
F(i)
的系数,所以我们需要将不同的p值的前缀和分别保存下来。注意此题当p大于19时,最小值也是1e6,所以直接输出m*n就好。我们预处理p从0到19的前缀和,注意到当p很大时,所有的
f(i)
都会被统计到
F(i)
中,所以我们从小到大处理就好。第二个代码的预处理思路类似,然而可能是由于局部性原理的原因,慢了100ms左右。
http://blog.csdn.net/wing_wuchen/article/details/76861929
249ms的代码:
#include<stdio.h>
#include <iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#define eps 1e-8
typedef long long int lli;
using namespace std;
const int maxn = 5e5+20;
bool isprime[maxn];
//int phi[maxn];
int prime[maxn],miu[maxn];
int cnt[maxn];
void moblus(){
int num = 0;miu[1] = 1;
for(lli i = 2;i < maxn;i++){
if(!isprime[i]){
prime[num++] = i,miu[i] = -1;//phi[i] = i-1;
cnt[i] = 1;
}
for(lli j = 0;j < num && i*prime[j] < maxn;j++){
lli x = prime[j];
isprime[i*x] = 1;cnt[i*x] = cnt[i]+1;
if(i%x){
miu[i*x] = -miu[i];
//phi[i*x] = phi[i] * phi[x];
}
else{
miu[i*x] = 0;
//phi[i*x] = phi[i] * x;
break;
}
}
}
}
int ff[maxn];bool v[maxn];
int sum[25][maxn];
int main(){
moblus();
for(int p = 0;p <= 19;p++){
for(int i = 1;i < maxn;i++){
if(cnt[i] > p || v[i]) continue;
v[i] = true;
for(int j = 1;j*i < maxn;j++){
ff[i*j] += miu[j];
}
}
for(int i = 1;i < maxn;i++){
sum[p][i] = sum[p][i-1]+ff[i];
}
}
int q,n,m,p;
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&n,&m,&p);
if(p > 19){
printf("%lld\n",(lli)m*(lli)n);
continue;
}
if(n>m) swap(n,m);
lli ans = 0,l;
for(int i = 1;i <= n;i=l+1){
l = min(n/(n/i),m/(m/i));
ans += (lli)(sum[p][l]-sum[p][i-1])*(lli)(n/i)*(lli)(m/i);
}
printf("%lld\n",ans);
}
return 0;
}
390ms的代码:
#include<stdio.h>
#include <iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#define eps 1e-8
typedef long long int lli;
using namespace std;
const int maxn = 5e5+20;
bool isprime[maxn];
//int phi[maxn];
int prime[maxn],miu[maxn];
int cnt[maxn];
void moblus(){
int num = 0;miu[1] = 1;
for(lli i = 2;i < maxn;i++){
if(!isprime[i]){
prime[num++] = i,miu[i] = -1;//phi[i] = i-1;
cnt[i] = 1;
}
for(lli j = 0;j < num && i*prime[j] < maxn;j++){
lli x = prime[j];
isprime[i*x] = 1;cnt[i*x] = cnt[i]+1;
if(i%x){
miu[i*x] = -miu[i];
//phi[i*x] = phi[i] * phi[x];
}
else{
miu[i*x] = 0;
//phi[i*x] = phi[i] * x;
break;
}
}
}
}
int sum[25][maxn];
int main(){
moblus();
for(int i = 1;i < maxn;i++){
for(int j = 1;j*i < maxn;j++){
sum[cnt[i]][i*j] += miu[j];//我觉得可能是这里 内存的局部性原理导致100ms的延迟吧
}
}
for(int i = 1;i < maxn;i++){
sum[0][i] = sum[0][i-1]+sum[0][i];
}
for(int p = 1;p <= 19;p++){
for(int i = 1;i < maxn;i++){
sum[p][i] = sum[p][i-1] + sum[p][i];
}
for(int i = 1;i < maxn;i++){
sum[p][i] += sum[p-1][i];
}
}
int q,n,m,p;
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&n,&m,&p);
if(p > 19){
printf("%lld\n",(lli)m*(lli)n);
continue;
}
if(n>m) swap(n,m);
lli ans = 0,l;
for(int i = 1;i <= n;i=l+1){
l = min(n/(n/i),m/(m/i));
ans += (lli)(sum[p][l]-sum[p][i-1])*(lli)(n/i)*(lli)(m/i);
}
printf("%lld\n",ans);
}
return 0;
}