[关闭]
@xiaoziyao 2021-03-29T23:39:50.000000Z 字数 2402 阅读 1119

P7451 [THUSCH2017] 杜老师解题报告

解题报告


P7451 [THUSCH2017] 杜老师解题报告:

更好的阅读体验

题意

给定组数据,每组数据询问区间中选出乘积为完全平方数的子集数量。(

分析

首先看到乘积为完全平方数的子集数量完全可以想到线性基(详见CF895C Square Subsets)。

那么我们有一个初步想法:把是否含有某个质数的奇次幂压成一个二进制数(用存储),然后对这些二进制数建立一个线性基,求的自由元数量次幂。

想法很好,但时间复杂度为,空间复杂度为,均会超过限制。(为不超过的质数数量,且

考虑根号分治,设,那么的质数最多只有个。

枚举中每一个数,进行质因数分解,不难发现的质因数最多一个,且是一次幂,那么我们可以把的质数的的质数的分开处理。

对于的质数,我们在质因数分解的时候处理出,然后插入线性基。

对于的质数,我们发现最多会有个有用的质数,每次遇到某个质数才建立某个线性基,那么只会建出很少的线性基,且每次插入的复杂度是的。

如果设,那么时间复杂度被我们优化到了,空间复杂度则是,仍然不能通过本题。

这里就要用到一个很玄妙的结论:如果区间长度大于,那么区间里的质数一旦出现就会出现在线性基内,然后我们枚举所有质数判断是否在这个区间内出现过就好了。

时间复杂度:,空间复杂度:

代码

  1. #include<stdio.h>
  2. #include<bitset>
  3. using namespace std;
  4. const int maxn=10000005,maxm=455,mod=998244353,t=3200;
  5. int T,A,B,cnt,tp;
  6. int sump[maxn],minn[maxn],ord[maxn],p[maxn],a[maxn],L[maxn],tmpord[maxn];
  7. bitset<maxm>tmp;
  8. bitset<maxm>b[maxm],l[maxm],val[t<<1];
  9. void sieve(int n){
  10. p[1]=1,sump[1]=0,minn[1]=1;
  11. for(int i=2;i<=n;i++){
  12. if(p[i]==0)
  13. a[++cnt]=i,ord[i]=cnt,minn[i]=i;
  14. for(int j=1;j<=cnt;j++){
  15. if(i*a[j]>n)
  16. break;
  17. p[i*a[j]]=1,minn[i*a[j]]=minn[i];
  18. if(i%a[j]==0)
  19. break;
  20. }
  21. sump[i]=sump[i-1]+(p[i]^1);
  22. }
  23. }
  24. int ksm(int a,int b){
  25. int res=1;
  26. while(b){
  27. if(b&1)
  28. res=1ll*res*a%mod;
  29. a=1ll*a*a%mod,b>>=1;
  30. }
  31. return res;
  32. }
  33. int insert(bitset<maxm>b){
  34. for(int i=tp;i>=1;i--){
  35. if(b[i]==0)
  36. continue;
  37. if(l[i].any()==false){
  38. l[i]=b;
  39. return 1;
  40. }
  41. b^=l[i];
  42. }
  43. return 0;
  44. }
  45. int main(){
  46. sieve(10000000);
  47. for(tp=1;a[tp]<=t;tp++);
  48. scanf("%d",&T);
  49. while(T--){
  50. scanf("%d%d",&A,&B);
  51. if(B-A+1>2*t){
  52. int res=B-A+1;
  53. for(int i=1;i<=cnt&&a[i]<=B;i++)
  54. if(B/a[i]!=(A-1)/a[i])
  55. res--;
  56. printf("%d\n",ksm(2,res));
  57. continue;
  58. }
  59. int res=0,tmps=0;
  60. for(int i=1;i<=tp;i++)
  61. l[i].reset();
  62. for(int i=A;i<=B;i++){
  63. int k=i,rec=minn[i];
  64. if(rec>t)
  65. k/=rec;
  66. tmp.reset();
  67. while(k>1){
  68. int w=minn[k],cnt=0;
  69. while(k%w==0)
  70. k/=w,cnt^=1;
  71. tmp[ord[w]]=cnt;
  72. }
  73. if(rec>t){
  74. if(tmpord[rec]==0){
  75. tmpord[rec]=++tmps,val[tmps]=tmp;
  76. continue;
  77. }
  78. tmp^=val[tmpord[rec]];
  79. }
  80. res+=(insert(tmp)^1);
  81. }
  82. for(int i=A;i<=B;i++)
  83. tmpord[minn[i]]=0;
  84. printf("%d\n",ksm(2,res));
  85. }
  86. return 0;
  87. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注