• BZOJ2005: [Noi2010]能量采集


    【传送门:BZOJ2005


    简要题意:

      给出n*m个格子,位置从(1,1)到(n,m)

      在(0,0)的位置上有一个机器,如果(x,y)这个点与(0,0)的连线上覆盖了k个点(不包括(0,0)和(x,y)),则这个点的代价为2*k+1

      求出所有n*m个点的代价和


    题解:

      莫比乌斯反演

      显然代价和等于$sum_{x=1}^{n}sum_{y=1}^{m}2*gcd(x,y)-1$,可以转化为$-n*m+2*sum_{x=1}^{n}sum_{y=1}^{m}gcd(x,y)$

      那么我们只要求出$sum_{x=1}^{n}sum_{y=1}^{m}gcd(x,y)$就可以了

      因为一个数的所有因子的欧拉函数之和等于这个数

      所以转化为$$sum_{x=1}^{n}sum_{y=1}^{m}sum_{d=1}^{n}[d|x且d|y]phi(d)$$

      交换和式得到$$sum_{d=1}^{n}sum_{x=1}^{n}[d|x]sum_{y=1}^{m}[d|y]phi(d)$$

      实际上就等于$sum_{d=1}^{n}frac{n}{d}*frac{m}{d}*phi(d)$

      预处理欧拉函数就可以了


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    int prime[110000],v[110000];
    LL phi[110000];
    void pre(int n)
    {
        memset(v,0,sizeof(v));
        int m=0;phi[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(v[i]==0)
            {
                v[i]=i;
                prime[++m]=i;
                phi[i]=i-1;
            }
            for(int j=1;j<=m;j++)
            {
                if(prime[j]>n/i||prime[j]>v[i]) break;
                v[prime[j]*i]=prime[j];
                if(i%prime[j]==0) phi[i*prime[j]]=phi[i]*prime[j];
                else phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
    int main()
    {
        pre(100000);
        int n,m;
        scanf("%d%d",&n,&m);
        LL ans=0;
        for(int i=1;i<=min(n,m);i++) ans+=(LL)(n/i)*(m/i)*phi[i];
        printf("%lld
    ",2*ans-(LL)n*m);
        return 0;
    }

     

  • 相关阅读:
    网址
    oracle一些笔记
    GLOBAL_NAMES参数研究
    创建 dblink
    解析grant connect, resource to user语句
    授权
    Bootstrap(转)
    C#操作XML小结(转)
    使用backbone.js、zepto.js和trigger.io开发HTML5 App
    SQLSERVER存储过程基本语法
  • 原文地址:https://www.cnblogs.com/Never-mind/p/9842045.html
Copyright © 2020-2023  润新知