NJUST 1922 容斥原理

来源:互联网 发布:广州汇丰软件 编辑:程序博客网 时间:2024/06/05 10:29

count_prime

Time Limit: 1000ms

Memory Limit: 65536KB


Description

给定你一个数n,请你统计出在[a,b]这个区间中和n互质的数的个数。两个数互质当且仅当他们除了1之外没有其他的公共因子或者他们最大的公共因子是1。1和任何数是互素的。

Input

第一行输入一个整数T(1 <= T <= 100),表示T组测试数据。接下来T行,每行3个整数a,b,n(1 <= a <=b <=10^15, 1<= n <= 10^9),用空格隔开。

Output

输出一个整数表示和n互质的数的个数。

Sample Input

2
1 10 2
3 10 5

Sample Output

5
6




 搞了一个多小时,终于弄懂了QAQ,容斥原理。

1-i中,是a的倍数和b的倍数的个数为i/a+i/b-i/(a*b)。
设有n个因子,求 1-i中这n个因子的倍数的个数。
定义变量k,从1开始,for到n,每for一次,任取k个因子相乘,如果是奇数个因子,就把当前值加上i/(k个因子的积),否则减去。


dfs 

cur代表当前的因子,now代表当前的乘积,neg代表奇或偶,mid代表i,res代表结果
f代表元素个数,fac代表因子数组0-(f-1)

void dfs(ll cur,ll now,bool neg,ll mid,ll &res){if(cur>=f)return;ll num=now*fac[cur]/gcd(now,fac[cur]);//这里是最小公倍数 不然会出错  比如是6或8的倍数且小于等于24  如果不是最小公倍数就会少减一个24dfs(cur+1,now,neg,mid,res);//搜不放这个因子的积if(neg)res=res+mid/num;else res=res-mid/num;dfs(cur+1,num,!neg,mid,res);//搜放这个因子的积} 

#include<iostream>  #include<stdio.h>  using namespace std;  typedef long long ll;  ll t,n,a,b,i,x,flag,sum,fac[105],f;  ll gcd(ll a,ll b){if(b==0)return a;return gcd(b,a%b);}void dfs(ll cur,ll now,bool neg,ll mid,ll &res){      if(cur>=f)return;      ll num=now*fac[cur]/(gcd(now,fac[cur]));      dfs(cur+1,now,neg,mid,res);      if(neg)res=res+mid/num;      else res=res-mid/num;      dfs(cur+1,num,!neg,mid,res);  }  int main(){      cin>>t;      while(t--){          cin>>a>>b>>n;          f=0;          ll so=0;          for(i=2;n!=1;i++){              while(n%i==0){                  if(so!=i){                      fac[f++]=i;                  }                  so=i;                  n/=i;              }          }          ll res=0;          dfs(0,1,1,a-1,res);          ll so1=a-1-res;          res=0;          dfs(0,1,1,b,res);          ll so2=b-res;          cout<<so2-so1<<endl;      }      return 0;  }  


0 0
原创粉丝点击