• 好数


    【问题描述】
    我们定义一个非负整数是“好数”,当且仅当它符合以下条件之一:
    1.这个数是0或1
    2.所有小于这个数且与它互质的正整数可以排成一个等差数列
    例如,8就是一个好数,因为1,3,5,7排成了等差数列。
    给出N个非负整数,然后进行如下三个操作:
    1.询问区间[L,R]有多少个好数
    2.将区间[L,R]内所有数对S取余(S≤1000000)
    3.将第C个数更改为X
    提示:如果你不知道如何判断一个数是否为好数,你可以打个表找找规律。

    【输入格式】
    输入文件名为good.in。
    第一行包含两个正整数N和M,M表示操作数目
    第二行包含N个非负整数。
    接下来的M行每行表示1个操作:“1 L R”表示第1个操作,“2 L R S”表示第2个操作,“3 C X”表示第3个操作。

    【输出格式】
    输出文件名为color.out。
    对每个操作1,输出一个非负整数,表示区间内好数的个数。

    【输入输出样例1】
    good.in
    3 6
    4 6 9
    1 1 3
    1 3 3
    2 1 1 10
    1 1 3
    3 2 4
    1 1 3
    good.out
    2
    0
    2
    2

    【输入输出样例2】
    good.in
    8 5
    12 24 17 31 16 21 18 30
    1 2 5
    2 4 7 7
    3 2 13
    1 1 8
    1 3 6
    good.out
    3
    6
    4

    【数据规模与约定】
    样例点编号 N M N个数大小(≤) 具有的操作
    1,2 100 100 100 1,2,3
    3,4 1000 1000 1000000 1,2,3
    5,6,7 100000 100000 1000000 1,3
    8,9,10 100000 100000 1000000 1,2,3

    【题解】
    20分做法:
    直接暴力判断区间内每个数是否是好数。

    40分做法:
    可以找规律发现好数的性质:它必须是质数、2的k次幂或者6。证明:如果不为质数,那么一定有2因子,否则1和2都与它互质。设为m*2^k(m是大于1的奇数),那么m+2和m-2与它互质,1和m*2^k – 1与它互质,数列确定为1,5,9,13,…,只有这个数为6的时候成立。
    于是可以预处理出好数,处理操作的时间复杂度O(N*M)

    70分做法:
    发现没有操作2,用基本的线段树/树状数组做。

    100分做法1:
    加上操作2后,可以发现每个数取余后要么不变化,要么小于原来的二分之一,因此每个数X变化的次数至多为log(X)次,因此可以暴力修改它。在线段树上加上一个记录区间最大值的数,如果当前取余的数S大于这段区间最大值,那么就不用在其上取余。

    100分做法2:
    仍用树状数组,只是在处理k=2的情况时,若其是否为好数的性质不变,即不修改。
    (但这样比前一种做法慢了不少)manlebushao

    这道题反映出我的一个问题:树状数组/线段树掌握不熟练。同时,树状数组的模板是给当前值加数,若要他变成一个值,加后者与前者之差即可。

    树状数组:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define ll long long
    #define re register
    #define il inline
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    int prime[1000001]={},cnt,n,m,c[100001]={},x,y,s,a[100001]={},t;
    bool vis[1000001]={};
    il int gi()
    {  
      re int x=0;
      re short int t=1;
      re char ch=getchar();
      while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    void add(int p,int v)
    {
        while(p<=n)
            a[p]+=v,p+=p&-p;
    }
    int pre(int p)
    {
        if(!p) return 0;
        int s;
        for(s=0;p;p-=p&-p)
            s+=a[p];
        return s;
    }
    void Prime(int n)
    {
        vis[1]=1;
        for(int i=2;i<=n;i++)
         {
            if(!vis[i])
             prime[++cnt]=i;
            for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
             {
                vis[i*prime[j]]=1;
                if(!(i%prime[j]))
                 break;
             }   
         }
    }
    int main()
    {
        freopen("good.in","r",stdin);
        freopen("good.out","w",stdout);
        Prime(1000000);
        vis[0]=0;vis[1]=0;vis[6]=0;
        fp(i,1,19)
            vis[1<<i]=0;//预处理好数
        n=gi();m=gi();
          fp(i,1,n)
            c[i]=gi(),add(i,!vis[c[i]]);
          fp(i,1,m)
          {
            int k=gi();x=gi();y=gi();
            if(k==1) printf("%d
    ",pre(y)-pre(x-1));
            if(k==2)
            {
                s=gi();
                fp(j,x,y)
                if(c[j]>=s)
                  {
                    int last=!vis[c[j]];
                    c[j]%=s;
                    add(j,!vis[c[j]]-last);
                  }
            }
            if(k==3)
            {
                int last=!vis[c[x]];
                add(x,!vis[y]-last);
                c[x]=y;
            }
          }
        return 0;
    }

    附上线段树做法:

    #include <bits/stdc++.h>
    #define il inline
    #define RG register
    #define ll long long
    #define N (1000010)
    #define ls (x<<1)
    #define rs (x<<1|1)
    
    using namespace std;
    
    int prime[N],vis[N],phi[N],a[N],n,m,cnt;
    int can[N<<2],mx[N<<2];
    
    il int gi(){
      RG int x=0,q=1; RG char ch=getchar();
      while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
      if (ch=='-') q=-1,ch=getchar();
      while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
      return q*x;
    }
    
    il void pre(){
      phi[1]=1;
      for (RG int i=2;i<N;++i){
        if (!vis[i]) prime[++cnt]=i,phi[i]=i-1;
        for (RG int j=1,k;j<=cnt;++j){
          k=i*prime[j]; if (k>=N) break; vis[k]=1;
          if (i%prime[j]) phi[k]=phi[i]*(prime[j]-1);
          else{ phi[k]=phi[i]*prime[j]; break; }
        }
      }
      for (RG int i=1;i<N;i<<=1) vis[i]=0; return;
    }
    
    il int check(RG int x){ return !vis[x] || phi[x]<=2; }
    
    il void pushup(RG int x){
      can[x]=can[ls]+can[rs];
      mx[x]=max(mx[ls],mx[rs]); return;
    }
    
    il void build(RG int x,RG int l,RG int r){
      if (l==r){ mx[x]=a[l],can[x]=check(a[l]); return; }
      RG int mid=(l+r)>>1;
      build(ls,l,mid),build(rs,mid+1,r);
      pushup(x); return;
    }
    
    il void update(RG int x,RG int l,RG int r,RG int p,RG int v){
      if (l==r){ mx[x]=v,can[x]=check(v); return; } RG int mid=(l+r)>>1;
      p<=mid ? update(ls,l,mid,p,v) : update(rs,mid+1,r,p,v);
      pushup(x); return;
    }
    
    il void updatemod(RG int x,RG int l,RG int r,RG int xl,RG int xr,RG int S){
      if (l==r){ mx[x]%=S,can[x]=check(mx[x]); return; }
      if (mx[x]<S) return; RG int mid=(l+r)>>1;
      if (xr<=mid) updatemod(ls,l,mid,xl,xr,S);
      else if (xl>mid) updatemod(rs,mid+1,r,xl,xr,S);
      else updatemod(ls,l,mid,xl,mid,S),updatemod(rs,mid+1,r,mid+1,xr,S);
      pushup(x); return;
    }
    
    il int query(RG int x,RG int l,RG int r,RG int xl,RG int xr){
      if (xl<=l && r<=xr) return can[x]; RG int mid=(l+r)>>1;
      if (xr<=mid) return query(ls,l,mid,xl,xr);
      else if (xl>mid) return query(rs,mid+1,r,xl,xr);
      else return query(ls,l,mid,xl,mid)+query(rs,mid+1,r,mid+1,xr);
    }
    
    int main(){
      n=gi(),m=gi(),pre();
      for (RG int i=1;i<=n;++i) a[i]=gi();
      build(1,1,n);
      for (RG int i=1,op,l,r,S,c,x;i<=m;++i){
        op=gi();
        if (op==1){
          l=gi(),r=gi();
          printf("%d
    ",query(1,1,n,l,r));
        }
        if (op==2){
          l=gi(),r=gi(),S=gi();
          updatemod(1,1,n,l,r,S);
        }
        if (op==3){
          c=gi(),x=gi();
          update(1,1,n,c,x);
        }
      }
      return 0;
    }
  • 相关阅读:
    webService客户端搭建(三)
    webService服务器端搭建(二)
    electron 编译 sqlite3避坑指南---尾部链接有已经编译成功的sqlite3
    解决网页中Waiting (TTFB)数据加载过慢的问题
    Node-sqlite3多字段插入数据问题
    win上使用nvm管理node版本
    centos系统设置局域网静态IP
    将win平台上的mysql数据复制到linux上报错Can't write; duplicate key in table
    win上配置nginx
    Nodejs解决所有跨域请求
  • 原文地址:https://www.cnblogs.com/yanshannan/p/7392302.html
Copyright © 2020-2023  润新知