zoukankan      html  css  js  c++  java
  • hdu 6134: Battlestation Operational (2017 多校第八场 1002)【莫比乌斯】

    题目链接

    比赛时没抓住重点,对那个受限制的“分数求和”太过关心了。。其实如果先利用莫比乌斯函数的一个性质把后面那个[gcd(i,j)=1]去掉,那么问题就可以简化很多。公式如下

    这和之前做过的一道题很相似。。(见http://www.cnblogs.com/Just--Do--It/p/7326572.html

    这个式子显然是可以用分块+预处理mu[i]前缀和的方法来做。

    预处理复杂度是O(n),分块解决单组询问复杂度是O(sqrt(n))

    求g[n]可以用递推式来解决。

    对比g[n]和g[n-1],可以发现,当i整除n-1时,n/i比(n-1)/i大1,另外,g[n]比g[n-1]多末尾一项n/n(此处“/”即向上取整的除,因为我太懒了,就不写那么标准了。。),由此可以找到规律,g[n]=g[n-1]+d[n-1]+1。(很巧,那道题也用到了d[n])

    代码如下

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    const int mod=1e9+7;
    const int maxn=1e6+5;
    int prime[maxn+5];
    bool check[maxn+5];
    int d[maxn+5];
    int mu[maxn+5];
    int sum[maxn+5];
    int min_prime_cnt[maxn+5];
    int g[maxn+5];
    
    void init()
    {
        mu[1]=1,d[1]=1;
        int tot=0;
        for(int i=2; i<=maxn; i++)
        {
            if(!check[i])
            {
                prime[tot++]=i;
                mu[i]=-1;
                min_prime_cnt[i]=1;
                d[i]=2;
            }
            for(int j=0; j<tot; j++)
            {
                int t=i*prime[j];
                if(t>maxn) break;
                check[t]=true;
                if(i%prime[j]==0)
                {
                    mu[t]=0;
                    min_prime_cnt[t]=min_prime_cnt[i]+1;
                    d[t]=d[i]/(min_prime_cnt[i]+1)*(min_prime_cnt[t]+1);
                    break;
                }
                else
                {
                    mu[t]=-mu[i];
                    d[t]=d[i]*2;
                    min_prime_cnt[t]=1;
                }
            }
        }
        g[1]=1;
        for(int i=2;i<=maxn;i++)    g[i]=(g[i-1]+d[i-1]+1)%mod;
        for(int i=1;i<=maxn;i++)    g[i]=(g[i]+g[i-1])%mod;
        for(int i=1;i<=maxn;i++)    sum[i]=sum[i-1]+mu[i];
    }
    
    int n;
    
    int main()
    {
        init();
        while(~scanf("%d",&n))
        {
            LL ans=0;
            for(int i=1, last; i<=n; i=last+1)
            {
                last=n/(n/i);
                ans=(ans+(sum[last]-sum[i-1])*g[n/i])%mod;
            }
            printf("%lld
    ",(ans+mod)%mod);
        }
    }
  • 相关阅读:
    secureCRT 6.5 ssh登陆openeuler提示交换秘钥不支持
    ediary电子日记本-力荐
    centos8.4 iso下载地址
    Manjaro Cutefish 安装体验类似macos风格
    脚本启动第一行提示sh/bash找不到
    securecrt双击克隆会话
    开源的window/linux远程连接工具-mRemoeteNG
    securecrt设置日志缓存
    怎么实现通过扫描二维码进行登录
    使用link rel="shortcut icon"为网页标题加图标
  • 原文地址:https://www.cnblogs.com/Just--Do--It/p/7384319.html
Copyright © 2011-2022 走看看