BZOJ 2301 Problem b

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2301

冬令营听了莫比乌斯,这就是宋老师上课讲的例题咯[今天来实现一下]

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 inline int in(){
 8     int x=0;char ch=getchar();
 9     while(ch>'9' || ch<'0') ch=getchar();
10     while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
11     return x;
12 }
13 
14 const int maxn=50010;
15 
16 int mu[maxn],s[maxn];
17 int Prime[maxn],cnt;
18 bool no_prime[maxn];
19 
20 void get_prime(){
21     int tmp;mu[1]=1;
22     for(int i=2;i<maxn;i++){
23         if(!no_prime[i]) Prime[++cnt]=i,mu[i]=-1;
24         for(int j=1;j<=cnt && ((tmp=Prime[j]*i)<maxn);j++){
25             no_prime[tmp]=true;
26             if(i%Prime[j]==0){mu[tmp]=0;break;}
27             mu[tmp]=-mu[i];
28         }
29     }
30     for(int i=1;i<maxn;i++) s[i]=s[i-1]+mu[i];
31 }
32 
33 //j表示在所有数x中n/x=n/i的最后一个
34 long long calcu(int n,int m){
35     long long sum=0;
36     if(n>m) swap(n,m);
37     for(int i=1,j=0;i<=n;i=j+1){
38         j=min(n/(n/i),m/(m/i));
39         sum+=(long long)(s[j]-s[i-1])*(m/i)*(n/i);
40     }
41     return sum;
42 }
43 
44 int main(){
45 #ifndef ONLINE_JUDGE
46     freopen("2301.in","r",stdin);
47     freopen("2301.out","w",stdout);
48 #endif
49 
50     int T,a,b,c,d,k;
51     long long ans;
52     
53     get_prime();
54     T=in();
55     while(T--){
56         a=in(),b=in(),c=in(),d=in(),k=in();
57         ans=calcu(b/k,d/k)-calcu(b/k,(c-1)/k)-calcu((a-1)/k,d/k)+calcu((a-1)/k,(c-1)/k);
58         printf("%lld\n",ans);
59     }
60 
61     return 0;
62 }
View Code

 

[感觉还是说一下怎么做吧...]不过建议大家还是找个ppt来看好啦[我没有图啊...]

首先将问题变成询问[i=1...n][j=1...m]中有多少gcd(i,j)==k的数

然后其实就是[i=1...n/k][j=1...m/k]中gcd(i,j)==1的数

然后设f(n,m,k)表示[i=1...n/k][j=1...m/k]中gcd(i,j)==1的个数

g(n,m,k)表示[i=1...n/k][j=1...m/k]中gcd(i,j)是1的倍数的个数 <- 小学生都知道这个等于(n/k)*(m/k)是吧

所以这一步直接由定义推来

然后莫比乌斯反演一下

 

然后再把g(n,m,k)的公式带一下

 

就是这个样子了...

然后发现有一大部分的数值是相同的,然后就可以看代码的分块了...

 

posted @ 2016-02-03 19:32  诚叙  阅读(...)  评论(...编辑  收藏