链接:https://ac.nowcoder.com/acm/contest/301/H
来源:牛客网
题描述
小乐乐上了一节数学课,数学老师讲的很好,小乐乐听的也如痴如醉。
小乐乐听了老师的讲解,知道了什么是素数,现在他想做几个习题。
现在题目来了:
首先我们先定义孤独的数:在一个区间中的一个数字x,如果他与这个区间中的任何数都互质,那么他就是孤独的数。
我们给定一个序列,然后接下来会有多次询问,对于每次询问,给定两个整数l, r,我想知道对于(a[l], a[l + 1], ...., a[r])区间来说中有多少孤独的数。
小乐乐听了老师的讲解,知道了什么是素数,现在他想做几个习题。
现在题目来了:
首先我们先定义孤独的数:在一个区间中的一个数字x,如果他与这个区间中的任何数都互质,那么他就是孤独的数。
我们给定一个序列,然后接下来会有多次询问,对于每次询问,给定两个整数l, r,我想知道对于(a[l], a[l + 1], ...., a[r])区间来说中有多少孤独的数。
分析:戴普 ,现在先当模板
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> const int MaxN = 1e5; using namespace std; int n, m, tot; int a[MaxN + 5], pri[MaxN + 5]; int pre[MaxN + 5], last[MaxN + 5], c[MaxN + 5]; vector <int> V[MaxN + 5], g[MaxN + 5]; int res[MaxN + 5]; bool vis[MaxN + 5]; struct NODE { int l, r, id; bool operator < (const NODE A) const { return l < A.l; } }query[MaxN + 5], seg[MaxN + 5]; bool cmp(NODE A, NODE B) { return A.r < B.r; } void Init() { for (int i = 2; i <= MaxN; i++) { if(!vis[i]) pri[++tot] = i; for (int j = 1; j <= tot && i * pri[j] <= MaxN; j++) { vis[i * pri[j]] = 1; if(i % pri[j] == 0) break; } } for (int i = 1; i <= tot; i++) { for (int j = pri[i]; j <= MaxN; j += pri[i]) V[j].push_back(pri[i]); } } void Add(int x, int w) { if(x == 0) return; for (int i = x; i <= MaxN; i += (i & (-i))) c[i] += w; } int Sigma(int x) { int res = 0; for (int i = x; i > 0; i -= (i & (-i))) res += c[i]; return res; } int main() { Init(); while(~scanf("%d%d", &n, &m)) { memset(c, 0, sizeof(c)); memset(pre, 0, sizeof(pre)); g[n + 1].clear(); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), g[i].clear(); for (int i = 1; i <= n; i++) { if(a[i] == 1) { seg[i].l = 0; } else { int Max = 0; for (int v : V[a[i]]) Max = max(Max, pre[v]); seg[i].l = Max; for (int v : V[a[i]]) pre[v] = i; } } for (int i = 0; i <= MaxN; i++) last[i] = n + 1; for (int i = n; i >= 1; i--) { if(a[i] == 1) seg[i].r = n + 1; else { int Min = n + 1; for (int v : V[a[i]]) Min = min(Min, last[v]); seg[i].r = Min; for (int v : V[a[i]]) last[v] = i; } } for (int i = 1; i <= n; i++) g[seg[i].r].push_back(i); for (int i = 1; i <= m; i++) scanf("%d%d", &query[i].l, &query[i].r), query[i].id = i; sort (query + 1, query + m + 1, cmp); int l = 0; for (int i = 1; i <= m; i++) { while(l + 1 <= n && l + 1 <= query[i].r) { Add(seg[l + 1].l, 1); for (int v : g[l + 1]) { Add(seg[v].l, -1); Add(v, 1); } l++; } res[query[i].id] = query[i].r - query[i].l + 1 - Sigma(query[i].r) + Sigma(query[i].l - 1); } for (int i = 1; i <= m; i++) printf("%d ", res[i]); } return 0; }
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 using namespace std; typedef unsigned long long ull; typedef long long ll; const int N = 1e5+7; int w[N],l[N],r[N];//l[i],r[i]保存第i个数的质因子出现的最左位置以及最右位置 vector<int>V[N];//V[i]存储的是j,其中r[j]=i vector<int>have[N],VPrime;//have[i]存储的是数字i分解的质因子,VPrime存储的是[1,200000]的素数 int ans[N];//存储结果 int flag[N]; struct node { int left,right,id; }p[N]; int cmp(node aa,node bb) { return aa.right<bb.right; } int ar[N]; int lowb(int t) { return t&(-t); } void add(int i,int v) { if(i==0) return; for(;i<N;ar[i]+=v,i+=lowb(i)); } int sum(int i) { int s=0; for(;i>0;s+=ar[i],i-=lowb(i)); return s; } void getHave(int index,int v) { int i=0; while(v>1&&i<VPrime.size()) { if(VPrime[i]*VPrime[i]>v) { have[index].push_back(v); break; } if(i<VPrime.size()&& v%VPrime[i]==0) { have[index].push_back(VPrime[i]); } while(i<VPrime.size()&& v%VPrime[i]==0) { v/=VPrime[i]; } i++; } } bool prime[N]; void init() { int i,j; memset(prime,0,sizeof(prime)); prime[1]=prime[0]=1; for(i=2;i<=N-2;i++) for(j=2;i*j<=N-2;j++) { prime[i*j]=1; } VPrime.clear(); for(i=2;i<=N-2;i++) { if(prime[i]==0) VPrime.push_back(i); } for(i=0;i<N;i++) { have[i].clear(); } for(i=2;i<N;i++) { getHave(i,i); } } void init2(int n)//计算出l数组,r数组以及V[] { for(int i=0;i<=n;i++) { V[i].clear(); } memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(flag,0,sizeof(flag)); for(int i=1;i<=n;i++) { int left=0; for(int j=0;j<have[w[i]].size();j++) { left=max(left,flag[have[w[i]][j]]); } l[i]=left; for(int j=0;j<have[w[i]].size();j++) { flag[have[w[i]][j]]=i; } } for(int i=1;i<N;i++)//这里要初始化为n+1 {flag[i]=n+1;} for(int i=n;i>=1;i--) { int right=n+1; for(int j=0;j<have[w[i]].size();j++) { right=min(right,flag[have[w[i]][j]]); } r[i]=right; for(int j=0;j<have[w[i]].size();j++) { flag[have[w[i]][j]]=i; } } for(int i=1;i<=n;i++) { V[r[i]].push_back(i); } } int main() { int i,j,k; int n,m,t; init(); while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0)) { for(i=1;i<=n;i++) { scanf("%d",&w[i]); } init2(n); for(i=1;i<=m;i++) { scanf("%d%d",&p[i].left,&p[i].right); p[i].id=i; } sort(p+1,p+1+m,cmp); memset(ar,0,sizeof(ar)); i=1; for(j=1;j<=m;j++) { while(i<=p[j].right) { add(l[i],1);//将左边notFit的+1 for(k=0;k<V[i].size();k++) { add(l[V[i][k]],-1);//将左边跟右边同时notFit的-1,去掉重复 add(V[i][k],1);//将右边notFit的+1 } i++; } int notFit=sum(p[j].right)-sum(p[j].left-1); ans[p[j].id]=p[j].right-p[j].left+1-notFit; } for(i=1;i<=m;i++) { printf("%d ",ans[i]); } } return 0; }