[NOIP2019模拟赛]数数(gcd)

题目大意:

  求l~r中有多少数与x互质,带单点修改

分析:

  两个30的部分分很好打:

    ·n<=1000暴力O(nq)就好了

    ·$a_i<=100$用树状数组维护每个x的前缀和就好了

  100分做法有两种,一种是莫比乌斯反演(我不会),还有一种就是bitset乱搞

  我们先筛法筛出所有质数(大概不到10000个)然后对于每个质数建立一个bitset,表示对于第i个数在有第j个质数这个质因子

  求有多少数与x互质转换为有多少数与x不互质就好了

  对于每次询问把所有x的质因子找出来然后把这些数的bitset或起来再用类似前缀和的方法维护即可

  时间复杂度$O(\frac{n*Q*logn}{32})$显然跑不满,所以卡一卡就过了(跑的比莫比乌斯反演快)

代码:(这里把两种部分分的打法也都写上了)

 

  1 #pragma GCC optimize("Ofast")
  2 #include<bits/stdc++.h>
  3 #define lowbit(x) (x&(-x))
  4 using namespace std;
  5 inline int read(){
  6     int ans=0,f=1;char chr=getchar();
  7     while(!isdigit(chr)){if(chr=='-')f=-1;chr=getchar();}
  8     while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
  9     return ans*f;
 10 }const int M = 5e4+5;
 11 int n,m,a[M],Q,ans,gcd[101][101];
 12 struct P{
 13     int s[M];
 14     void Update(int x,int a){for(;x<=n;x+=lowbit(x)) s[x]+=a;}
 15     int Query(int x){int res=0;for(;x;x-=lowbit(x)) res+=s[x];return res;} 
 16 }t[101];
 17 //-------------------------------------------------第一个30pts --------------------------------------------------
 18 inline void Solve_1(){//n*Q<=1000000
 19     while(Q--){
 20         int opt=read(),x;
 21         if(opt==1)    x=read(),a[x]=read();
 22         else{
 23             int l=read(),r=read();
 24             x=read();ans=0;
 25             for(int i=l;i<=r;i++)
 26                 if(__gcd(x,a[i])==1)
 27                     ++ans;
 28             printf("%d\n",ans);
 29         }
 30     }
 31 }
 32 //---------------------------------------第二个30pts ----------------------------------------------------- 
 33 inline void Solve_2(){//Ai<=100
 34     for(int i=1;i<=100;++i)
 35         for(int j=1;j<=100;++j)
 36             gcd[i][j]=__gcd(i,j);
 37     for(int i=1;i<=100;i++)
 38         for(int j=1;j<=n;j++)
 39             if(gcd[i][a[j]]==1)
 40                 t[i].Update(j,1);
 41     while(Q--){
 42         int opt=read();
 43         if(opt==1){
 44             int x=read(),y=read(),tt=a[x];
 45             a[x]=y;
 46             for(int i(1);i<=100;++i){
 47                 if(gcd[a[x]][i]!=1&&gcd[tt][i]==1)
 48                     t[i].Update(x,-1);
 49                 if(gcd[a[x]][i]==1&&gcd[tt][i]!=1)
 50                     t[i].Update(x,1);
 51             }
 52         }else{int l=read(),r=read(),x=read();
 53             printf("%d\n",t[x].Query(r)-t[x].Query(l-1));
 54         }
 55     }
 56 }bitset<M>s[10000],now;
 57 int v[M*2],pri[M*2],tot;
 58 //----------------------------------------通解-------------------------------------------- 
 59 inline void Get_Pri(){
 60     for(int i=2;i<=100000;i++){
 61         if(!v[i]) v[i]=i,pri[++tot]=i;
 62         for(int j=1;j<=tot;j++){
 63             if(pri[j]>100000/i||pri[j]>v[i]) break;
 64             v[i*pri[j]]=pri[j];
 65         }
 66     }
 67 }
 68 inline void Update(int pos,int x,int y){
 69     int i=1;
 70     while(1){
 71         if(pri[i]*pri[i]>x) break;
 72         if(x%pri[i]==0){
 73             s[i][pos]=y;
 74             while(x%pri[i]==0) x/=pri[i];
 75         }i++;
 76     }if(x>1)s[lower_bound(pri+1,pri+tot+1,x)-pri][pos]=y;
 77 }
 78 inline void Solve(){
 79     Get_Pri();
 80     for(int i=1;i<=n;i++) Update(i,a[i],1);
 81     while(Q--){
 82         int opt=read();
 83         if(opt==1){
 84             int x=read(),y=read();
 85             Update(x,a[x],0),Update(x,y,1);
 86             a[x]=y;
 87         }else{
 88             int l=read(),r=read(),x=read();
 89             int i=1;now=0;
 90             while(1){
 91                 if(pri[i]*pri[i]>x) break;
 92                 if(x%pri[i]==0){
 93                     now|=s[i];
 94                     while(x%pri[i]==0) x/=pri[i];
 95                 }i++;
 96             }if(x>1) now|=s[lower_bound(pri+1,pri+tot+1,x)-pri];
 97             int Ans=r-l+1-(now>>l).count()+(now>>(r+1)).count();
 98             printf("%d\n",Ans);
 99         }
100     }
101 }
102 int main(){
103     freopen("gcd.in","r",stdin);
104     freopen("gcd.out","w",stdout);
105     n=read();
106     for(int i=1;i<=n;++i) a[i]=read();
107     Q=read();
108 //    if(n*Q<=1000000) Solve_1();
109 //    else Solve_2();
110     Solve();
111     return 0;
112 }

 

posted @ 2019-08-12 08:11  zheng_liwen  阅读(291)  评论(0编辑  收藏  举报
/*去广告*/