容斥原理

来源:互联网 发布:linux配置ftp 编辑:程序博客网 时间:2024/06/05 05:46

之前知道简单的容斥原理。。但是多个还真的不是非常会。。

今天遇到了一个题,就卡在这里了。。
于是去补了一发

问题提出

给出范围n
然后给你m个数
问你在1~n这个范围类,满足i是m个数中其中一个数的倍数的i个个数

解法

常见的写法有三种,dfs,队列数组,位运算。
然后队列数组没找到怎么写。。

void dfs (LL x,LL now,LL lalal)//现在的值是多少    取到第几个数了    取了多少个数{    if (x>b) return ;    if (now>cntt)    {        if (x==1) return ;        if (lalal%2!=0) ans=ans+(b/x);        else ans=ans-b/x;        return ;    }    dfs(x,now+1,lalal);    LL nn=x/gcd(x,g[now]);    if ((double)nn*g[now]>b) return ;    dfs(nn*g[now],now+1,lalal+1);}

然后位运算的原理是一样的,就不写了。。
贴一个别人的吧(这个板子是对n这个数的质因数的):

LL Solve(LL n,LL r)  {      vector<LL> p;      for(LL i=2; i*i<=n; i++)      {          if(n%i==0)          {              p.push_back(i);              while(n%i==0) n/=i;          }      }      if(n>1)          p.push_back(n);      LL ans=0;      for(LL msk=1; msk<(1<<p.size()); msk++)      {          LL multi=1,bits=0;          for(LL i=0; i<p.size(); i++)          {              if(msk&(1<<i))  //判断第几个因子目前被用到              {                  ++bits;                  multi*=p[i];              }          }          LL cur=r/multi;          if(bits&1) ans+=cur;          else       ans-=cur;      }      return r-ans;  }  

或许有人会想,两个数相乘的时候为什么要除以gcd呢?
这个啊,我觉得我不用做过多的解释,你自己把它删掉,跑几组数据你就会知道了

原创粉丝点击