zoukankan      html  css  js  c++  java
  • 洛谷 1447 [NOI2010]能量采集——容斥/推式子

    题目:https://www.luogu.org/problemnew/show/P1447

    1.容斥原理

      求 f [ i ] 表示 gcd==i 的对数,先 f [ i ] = (n/i) * (m/i),再考虑减去不合法的对数。

      不合法就是不互质,也就是还有别的公因数,即还能再除。直接算会重复,不如限定求出 gcd==j 的对数。

      利用更大的 f [ ] 即可。在 n/i 和 m/i 的基础上 gcd==j 的对数就是 f [ i*j ]。所以要倒推。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=1e5+5;
    int n,m;
    ll ans,f[N],s[N];
    int main()
    {
        scanf("%d%d",&n,&m);
        if(n>m)swap(n,m);
        for(int d=n;d;d--)
        {
            f[d]=(ll)(n/d)*(m/d);//!!!下取整! 
            for(int k=2;k*d<=n;k++)f[d]-=f[k*d];
            ans+=f[d]*(d*2-1);
        }
        printf("%lld
    ",ans);
        return 0;
    }

    2.推式子

      ∑ ∑ (gcd(i,j)*2-1) == ∑ ∑ ( ( ∑phi(d) )*2-1 ) == 2*∑ phi(d) ∑ ∑ - n*m == 2*∑ phi(d) * (n/d) * (m/d) - n*m。

      值得注意的是phi[1]应该视作等于1。因为小于等于1的和1gcd==1的数有1个。

      没错,d==1的时候就是把n和m都弄上了。考虑那个 d|i && d|j ,d==1就是出现在每个地方。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=1e5+5;
    int n,m,phi[N],pri[N],cnt;
    ll ans;
    int main()
    {
        scanf("%d%d",&n,&m);if(n>m)swap(n,m);
        for(int i=2;i<=n;i++)
        {
            if(!phi[i])pri[++cnt]=i,phi[i]=i-1;
            for(int j=1;j<=cnt&&i*pri[j]<=n;j++)
                if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
                else phi[i*pri[j]]=phi[i]*(pri[j]-1);
            ans+=(ll)phi[i]*2*(n/i)*(m/i);
        }
        ans+=2ll*n*m;
        printf("%lld
    ",ans-(ll)n*m);
        return 0;
    }
  • 相关阅读:
    makefile学习之路
    DiagramDesigner的学习心得一
    MvvmLight的Message使用
    MvvmLight学习心得三
    Nancy学习心得一
    WPF的类似WinForm中的托盘
    py学习记录#10
    PY期末习题全解析
    py学习记录#11
    PY学习记录#9
  • 原文地址:https://www.cnblogs.com/Narh/p/9388280.html
Copyright © 2011-2022 走看看