Hdu 1695 GCD (数论 容斥原理)

落日映苍穹つ 2022-08-26 08:10 253阅读 0赞

参考了:HDU 1695 GCD 【数论,容斥原理】 - 脑残 - 博客频道 - CSDN.NET

题意:求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d)。

思路:问题可以转化:在b和d分别除以k之后的区间里,只需要求gcd(x, y) = 1就可以了。

题目还要求1-3 和 3-1 这种情况算成一种,因此需要限制x<y。

只需要枚举x,然后确定另一个区间里面有多少个y就可以了。因此问题转化成为区间(1, d)里面与x互素的数的个数

①(1…b)与(1…b)中有多少对数互质
②(1…b)与(b+1…d)中有多少对数互质

问题1就是欧拉函数的应用,下面的代码没有用这个,直接和问题2一起解决,牺牲了一些速度。

问题2从反面考虑,对于(b+1…d)中的每一个y,要想知道(1…b)中有多少数与它互质,
我们只需要知道多少个数与它不互质即可。而两个数不互质就意味着它们有公因子。
对于每一个y的因子f,都能确定地知道(1…b)中有多少个数含有因子f,用容斥原理算一下,
就能知道(1…b)中有多少个数与y互质了。枚举y即可解决问题。

如果w是x的因子,则(1,d)中是w倍数的数共有d/w个。

容斥原理:所有不与x互素的数的个数= 1个因子倍数的个数 - 2个因子乘积的倍数的个数 + 3个……-……

以下转自AC神:http://hi.baidu.com/aekdycoin/item/4c8d4089e5011759840fabad

关于区间gcd统计的小问题
1.求[1,n]内和n的gcd=k的个数
转换为求区间[1,n/k]内和n/k互质的数的个数
2.求[1,m]内和n互质的数的个数
容斥原理
3.求[1,m]内和n的gcd=k的个数
转化模型,同上

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <vector>
  4. #include <algorithm>
  5. using namespace std;
  6. #define min(a,b) ((a)<(b)?(a):(b))
  7. const int N=100005;
  8. vector<int> data[N];
  9. bool tag[N];
  10. void Prime ()
  11. {//预处理素数,同时记录每一个数的素因子
  12. int i,j;
  13. memset(tag,false,sizeof(tag));
  14. for (i=0;i<N;i++)
  15. data[i].clear();
  16. for (j=2;j<N;j+=2)
  17. data[j].push_back(2);
  18. for (i=3; i<N; i+=2) if (tag[i]==false)
  19. for (j=i;j<N;j+=i)
  20. {
  21. tag[j] = true;
  22. data[j].push_back(i);
  23. }
  24. }
  25. int Deal (int u,int state,int id)
  26. {
  27. int cnt=0,v=1; //v 因子
  28. for (int i=0; i<data[id].size(); i++)
  29. if ((1<<i) & state)
  30. {
  31. cnt++;
  32. v *= data[id][i];
  33. }
  34. int all=u/v;
  35. if (cnt%2==0)
  36. return -all;
  37. else
  38. return all;
  39. }
  40. int main ()
  41. {
  42. Prime();
  43. int T;
  44. scanf("%d", &T);
  45. for (int Cas=1;Cas<=T;Cas++)
  46. {
  47. int b,d,k;
  48. scanf("%*d%d%*d%d%d",&b,&d,&k);
  49. if (k==0)
  50. {
  51. printf("Case %d: 0\n",Cas);
  52. continue;
  53. }
  54. b/=k;
  55. d/=k;
  56. if (b>d)
  57. swap(b,d);
  58. __int64 ans=0;
  59. for (int i=1;i<=d;i++)
  60. {//枚举y,求1~d中与x互素的个数
  61. int x=min(i,b);
  62. ans+=x; //假设全都互素,然后减掉不互素的
  63. for (int j=1;j<(1<<data[i].size());j++)
  64. ans -= Deal(x,j,i);
  65. }
  66. printf("Case %d: %I64d\n",Cas,ans);
  67. }
  68. return 0;
  69. }

发表评论

表情:
评论列表 (有 0 条评论,253人围观)

还没有评论,来说两句吧...

相关阅读

    相关 HDU1695GCD

    原来用莫比乌斯写过这个[传送门][Link 1],发现这个用容斥挺好理解,就是跑的比莫比乌斯慢,莫比乌斯跑了40ms,这个跑了400ms。 估计复杂度是O(n\6\2^6)大