[SPOJ VLATTICE]Visible Lattice Points 數論 莫比烏斯反演
7001. Visible Lattice PointsProblem code: VLATTICE |
Consider a N*N*N lattice. One corner is at (0,0,0) and the opposite one is at (N,N,N). How many lattice points are visible from corner at (0,0,0) ?
A point X is visible from point Y iff no other lattice point lies on the segment joining X and Y.
Input :
The first line contains the number of test cases T. The next T lines contain an interger N
Output :
Output T lines, one corresponding to each test case.
Sample Input :
3
1
2
5
Sample Output :
7
19
175
Constraints :
T <= 50
1 <= N <= 1000000
題目大意
給定n*n*n的立方體,每一個整數點除(0。0。0)之外都有一盞燈(抽象理解),問能看到多少盞燈(被蓋住的燈不算)
解題思路
莫比烏斯反演/容斥原理的典型應用
用容斥原理來解釋就是三個點都能被k整除的個數乘上莫比烏斯系數,求和就可以
而三個點都能被k整除的個數就是floor(n/i)^3
註意到最大數據量為1000000 直接線性處理的辦法可能TLE
而(n/i)在後面i>(n/2)的部分結果都為1 能夠省去一次次計算,直接按mu的前綴和來處理
則我們就統計同樣(n/i)的值是否出現兩次。假設出現兩次那麽我們就開始依照前綴和的方法來處理
不優化 6200ms
優化後 490ms
code
優化前
#include <cstdio> #include <iostream> #include <algorithm> #include <ctime> #include <cctype> #include <cmath> #include <string> #include <cstring> #include <stack> #include <queue> #include <list> #include <vector> #include <map> #include <set> #define sqr(x) ((x)*(x)) #define LL long long #define INF 0x3f3f3f3f #define PI acos(-1.0) #define eps 1e-10 #define mod 100000007ll using namespace std; LL n; LL com[1000005],pri[1000005],phi[1000005],pn,sum[1000005],mu[1000005]; LL a[1000005]; int main() { memset(com ,0 ,sizeof com); mu[1]=1; for (int i=2;i<=1000000ll;i++) { if (com[i]==0) { phi[i]=i-1; pri[++pn]=i; mu[i]=-1; // printf("%d\n", pri[pn]); // system("pause"); } for (int j=1;j<=pn&&pri[j]*i<=1000000ll;j++) { if (i%pri[j]) { phi[i*pri[j]]=phi[i]*(pri[j]-1); com[i*pri[j]]=1; mu[i*pri[j]]=-mu[i]; } else { phi[i*pri[j]]=phi[i]*(pri[j]); com[i*pri[j]]=1; mu[i*pri[j]]==0; break; } } } sum[0]=0; for (int i=1;i<=1000000ll;i++) sum[i]=sum[i-1]+phi[i]; int T; scanf("%d",&T); while (T--) { // n=1000000; LL ans=0; scanf("%lld",&n); for (int i=n;i;i--) { a[i]=(n/i)*(n/i)*(n/i); ans+=a[i]*mu[i]; } printf("%lld\n",ans+(sum[n]*2+1)*3+3); } return 0; }
優化後
#include <cstdio> #include <iostream> #include <algorithm> #include <ctime> #include <cctype> #include <cmath> #include <string> #include <cstring> #include <stack> #include <queue> #include <list> #include <vector> #include <map> #include <set> #define sqr(x) ((x)*(x)) #define LL long long #define INF 0x3f3f3f3f #define PI acos(-1.0) #define eps 1e-10 using namespace std; int mu[1000005]; int com[1000005]; int pri[1000005],pn=0; int phi[1000005]; LL presum[1000005]; int musum[1000005]; int main() { memset(com,0,sizeof com); presum[1]=0; mu[1]=1; phi[1]=0; for (int i=2;i<=1000000;i++) { if (com[i]==0) { pri[++pn]=i; mu[i]=-1; phi[i]=i-1; } for (int j=1;j<=pn&&pri[j]*i<=1000000;j++) { if (i%pri[j]) { mu[i*pri[j]]=-mu[i]; com[i*pri[j]]=1; phi[i*pri[j]]=phi[i]*(pri[j]-1); } else { phi[i*pri[j]]=phi[i]*(pri[j]); mu[i*pri[j]]=0; com[i*pri[j]]=1; break; } } presum[i]=presum[i-1]+phi[i]; musum[i]=musum[i-1]+mu[i]; } int T; scanf("%d",&T); int a,b,c,d,k; while (T--) { int n; LL ans=0; scanf("%d",&n); int i; for (i=1;i<=n;i++) if ((n/i)==(n/(i+1))) break; else ans+=(LL)(n/i)*(n/i)*(n/i)*mu[i]; for (int j=(n/i);j;j--) ans+=(LL)(j)*(j)*(j)*(musum[n/(j)]-musum[n/(j+1)]); ans+=(LL)presum[n]*6+6; printf("%lld\n",ans); } return 0; }
[SPOJ VLATTICE]Visible Lattice Points 數論 莫比烏斯反演