題目:
我是超連結 題意:
niconico數:所有比x小的數且與x互質的數,從小到大排列是一個等差數列,則x為niconico數。
長度為10^5的數組。三種操作:
第一:詢問區間[l,r] niconico數的個數
第二:將區間 [ l , r ] 的數對v模數
第三:將某一個數更新為x 題解:
首先我們打個表看看這個數,然後我們可以發現,一個數是niconico數有以下3種情況 是質數 是2^x 是6
真是坑人,0&1也屬於niconico。。 代碼:
#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int N=100005;const int C=1e7;bool vis[C+5],ss[C+5];int pri[C+5],sum[N*4],maxx[N*4],tot,a[N];void init(){ for (int i=2;i<=C;i++) { if (!ss[i]) vis[i]=true,pri[++tot]=i; for (int j=1;j<=tot && pri[j]*i<=C;j++) { ss[pri[j]*i]=1; if (i%pri[j]==0) break; } } for (int i=2;i<=C;i*=2) vis[i]=1; vis[6]=vis[1]=vis[0]=1;}void updata(int now){ sum[now]=sum[now<<1]+sum[now<<1|1]; maxx[now]=max(maxx[now<<1],maxx[now<<1|1]);}void build(int now,int l,int r){ if (l==r) { maxx[now]=a[l]; sum[now]=(vis[a[l]]?1:0); return; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); updata(now);}int qurry(int now,int l,int r,int lrange,int rrange){ if (lrange<=l && rrange>=r) return sum[now]; int mid=(l+r)>>1,ans=0; if (lrange<=mid) ans+=qurry(now<<1,l,mid,lrange,rrange); if (rrange>mid) ans+=qurry(now<<1|1,mid+1,r,lrange,rrange); return ans;}void change(int now,int l,int r,int x,int v){ if (l==r) { maxx[now]=v; sum[now]=(vis[maxx[now]]?1:0); return; } int mid=(l+r)>>1; if (x<=mid) change(now<<1,l,mid,x,v); else change(now<<1|1,mid+1,r,x,v); updata(now);}void qm(int now,int l,int r,int lrange,int rrange,int x){ if (maxx[now]<x) return; if (l==r) { maxx[now]%=x; sum[now]=(vis[maxx[now]]?1:0); return; } int mid=(l+r)>>1; if (lrange<=mid) qm(now<<1,l,mid,lrange,rrange,x); if (rrange>mid) qm(now<<1|1,mid+1,r,lrange,rrange,x); updata(now);}int main(){ init();int n,m,id; while (scanf("%d",&n)!=EOF) { for (int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); scanf("%d",&m); for (int i=1;i<=m;i++) { int l,r,x;scanf("%d",&id); if (id==1) { scanf("%d%d",&l,&r);printf("%d\n",qurry(1,1,n,l,r)); }else if (id==2) { scanf("%d%d%d",&l,&r,&x); qm(1,1,n,l,r,x); }else { scanf("%d%d",&l,&x); change(1,1,n,l,x); } } }}