zoukankan      html  css  js  c++  java
  • 容斥——不和睦三元组(再次用到了筛法优化,长点心)

    和睦数三元组的个数问题

           给出一个整数 。选出a, b, c (其中2<=a<b<c<=n),组成和睦三元组,即:

             · 或者满足 ,  , 

    · 或者满足

    首先,我们考虑它的逆问题:也就是不和睦三元组的个数。

    然后,我们可以发现,在每个不和睦三元组的三个元素中,我们都能找到正好两个元素满足:它与一个元素互素,并且与另一个元素不互素。

    所以,我们只需枚举2到n的所有数,将每个数的与其互素的数的个数和与其不互素的数的个数相乘,最后求和并除以2,就是要求的逆问题的答案。

    现在我们要考虑这个问题,如何求与2到n这些数互素(不互素)的数的个数。虽然求解与一个数互素数的个数的解法在前面已经提到过了,但在此并不合适,因为现在要求2到n所有数的结果,分别求解显然效率太低。

    所以,我们需要一个更快的算法,可以一次算出2到n所有数的结果。

    这里注意一下,判断两个数是不是互素,将这两个数字唯一分解,然后看有没有相同的数根就ok了。也正是应为这个,这里可以用容斥和筛法处理这个问题。

    在这里,我们可以使用改进的埃拉托色尼筛法

    · 首先,对于2到n的所有数,我们要知道构成它的素数中是否有次数大于1的,为了应用容斥原理,我们还有知道它们由多少种不同的素数构成。

    对于这个问题,我们定义数组deg[i]:表示i由多少种不同素数构成,以及good[i]:取值true或false,表示i包含素数的次数小于等于1是否成立。

    再利用埃拉托色尼筛法,在遍历到某个素数i时,枚举它在2到n范围内的所有倍数,更新这些倍数的deg[]值,如果有倍数包含了多个i,那么就把这个倍数的good[]值赋为false。

    · 然后,利用容斥原理,求出2到n每个数的cnt[i]:在2到n中不与i互素的数的个数。

    回想容斥原理的公式,它所求的集合是不会包含重复元素的。也就是如果这个集合包含的某个素数多于一次,它们不应再被考虑。

    所以只有当一个数i满足good[i]=true时,它才会被用于容斥原理。枚举i的所有倍数i*j,那么对于i*j,就有N/i个与i*j同样包含i(素数集合)的数。将这些结果进行加减,符号由deg[i](素数集合的大小)决定。如果deg[i]为奇数,那么我们要用加号,否则用减号。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define MAXN 1009
    using namespace std;
    int n;
    int good[MAXN];
    int deg[MAXN], cnt[MAXN];
    long long solve() 
    {
        int ans=0;
        memset(cnt,0,sizeof(cnt));
        memset(deg,0,sizeof(deg));
        fill(good,good+MAXN,1);
        for(int i=2;i<=n;i++)
        {
            if(good[i])
            {
                if(deg[i]==0) deg[i]=1;
                for(int j=1;j*i<=n;j++) // 目的是要筛出不同素数的乘积
                {
                    if(j>1 && deg[i]==1 )// 当i为素数的时候,我们才筛去和i具有相同数根的数字
                    {
                        if(j%i==0) good[i]=0;
                        else deg[i*j]++;
                    }
                    if(deg[i*j]%2) cnt[i*j]+=n/i;
                    else cnt[i*j]-=n/i;
                }
            }
            ans+=cnt[i];
        }
    }
    int main()
    {
        n=100;
        solve();
        return 0;
    }
    View Code

    最后小结一下,关于筛法的问题。对于多个要求解的目标,如果这些目标都是可以通过前面的一点特定的数推算而来,就适用于筛法。(后来想了想,貌似和树根有关系的题目,都可以考虑一下要不要用筛法优化)。

  • 相关阅读:
    你不知道的JavaScript(上)作用域与闭包
    csu 1982: 小M的移动硬盘
    csu 1985: 驱R符
    csu 1987: 绚丽的手链
    2017ACM/ICPC广西邀请赛 1007 Duizi and Shunzi
    2017ACM/ICPC广西邀请赛 1005 CS Course
    2017ACM/ICPC广西邀请赛 1004 Covering
    hdu 1209 Clock
    trac中wiki直接显示任务代码
    phpcms中action值的含义
  • 原文地址:https://www.cnblogs.com/z1141000271/p/7298186.html
Copyright © 2011-2022 走看看