zoukankan      html  css  js  c++  java
  • UVA

    给定一个n*n*n的立方体(中心点为原点O),选择尽量多的点,使得对于任意两点A,B,B不在线段OA上。

    可以发现,原问题可转化为三维坐标下的点(x,y,z)中有多少个点的gcd(x,y,z)=1。

    这道题我一开始想用欧拉函数做,但我发现需要求出1-n中与每个整数x互质的数的个数,于是试图修改一下欧拉函数的公式,结果发现计算出来的结果存在微小的偏差,原因是n不一定能被x的所有因子整除,使得(n/p)*(n/q)≠n/pq。被逼无奈,于是学了莫比乌斯反演。

    莫比乌斯反演的做法是:令$n=n/2$,在$1leqslant x,y,zleqslant n$的限制条件下,设$f(X)$为$gcd(x,y,z)=X$的点的个数,$F(X)$为$gcd(x,y,z)=kX$的点的个数,则$F(X)=sumlimits_{X|d}f(d)$,根据莫比乌斯反演定理则有$f(X)=sum limits_{X|d}mu (frac{d}{X})F(d)$,$f(1)$即为$x,y,z$均大于0情况下的答案。由于又有$F(X)=left lfloor frac{n}{X} ight floor^3$,因此可以在$O(n)$的时间内算出$f(X)$。

    然后用同样的方法可以算出$x,y,z$中有一个为0,另外两个大于0情况下的答案,将$F(X)$换为$left lfloor frac{n}{X} ight floor^2$即可。

    一共有8个卦限,坐标平面上的12个象限,将结果乘一乘加一加,再加上在坐标轴上的6种情况,就得到答案了。

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 typedef long long ll;
     5 const ll N=1e5+10;
     6 ll n,mu[N],d[N],c[N],ka;
     7 void init() {
     8     mu[1]=1;
     9     for(ll i=1; i<N; ++i)if(mu[i])
    10             for(ll j=i*2; j<N; j+=i)mu[j]-=mu[i];
    11 }
    12 ll F1(ll x) {return (n/x)*(n/x)*(n/x);}
    13 ll F2(ll x) {return (n/x)*(n/x);}
    14 ll f(ll x,ll F(ll)) {
    15     ll ret=0;
    16     for(ll i=x; i<=n; i+=x)ret+=F(i)*mu[i/x];
    17     return ret;
    18 }
    19 
    20 int main() {
    21     init();
    22     while(scanf("%lld",&n)&&n) {
    23         n/=2;
    24         printf("Crystal %lld: %lld
    ",++ka,f(1,F1)*8+f(1,F2)*12+6);
    25     }
    26     return 0;
    27 }

    还可以进一步优化,利用整除分块的方法,将复杂度降到$O(sqrt n)$

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 typedef long long ll;
     5 const ll N=1e5+10;
     6 ll n,mu[N],smu[N],ka,ans;
     7 void init() {
     8     mu[1]=1;
     9     for(ll i=1; i<N; ++i)if(mu[i])
    10             for(ll j=i*2; j<N; j+=i)mu[j]-=mu[i];
    11     for(ll i=1; i<N; ++i)smu[i]=smu[i-1]+mu[i];
    12 }
    13 
    14 int main() {
    15     init();
    16     while(scanf("%lld",&n)&&n) {
    17         n/=2;
    18         ans=0;
    19         for(ll l=1,r; l<=n; l=r+1) {
    20             ll t=n/l;
    21             r=n/t;
    22             ans+=(t*t*t*8+t*t*12)*(smu[r]-smu[l-1]);
    23         }
    24         ans+=6;
    25         printf("Crystal %lld: %lld
    ",++ka,ans);
    26     }
    27     return 0;
    28 }

     以上筛莫比乌斯函数的方法复杂度是$O(nlogn)$的,也可以换成复杂度更低的$O(n)$的线性筛法,只是代码略长,不再赘述了。

  • 相关阅读:
    Java语言基础学习笔记——基础语法
    JAVA语言基础——java的编译和运行
    Java语言基础 ——注释
    Java语言基础—— 在控制台输入
    再也不为正则表达式愁了,只是调用几个函数的事情
    Java语言基础——数据类型转换
    Java语言基础学习笔记——面向对象
    Java语言基础——数据类型
    二进制,十进制,八进制,十六进制之间的转换
    Java语言基础——java 变量
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10356295.html
Copyright © 2011-2022 走看看