题意:给出n个数,有m个查询,每次查询询问区间[L,R]中最多有多少个数与区间中其他数都不互质。
思路:首先预处理一下,把每个数的因子求出来(不包含1,因为1和任何数都互质),这个比较简单……然后再预处理一下第i个数向左最小的和它不互质的数的位置和第i个数向右和它不互质的数的位置(用lf[i]和rn[i]表示)。接下来的操作比较烦,不太好理解。先说下大体思路吧,把所有操作存起来,然后从左到右依次向树状数组里插入,我开始想的是在树状数组每个位置有一个数,一个区间的不互质的和就是区间的和,这样就要让区间的某些位置加一些数,另一些位置减一些数,这个是肯定能构造出来的。那么如何去做呢。
先看一下这个数据吧: 3 6 1 2 5 3
就第4个数来说,构造出来的数就是:0 -1 1 1
这样对于区间为i的查询就可以求出答案了。
构造这个序列的方法如下:
①在第i位+1,在lf[i]-1处-1(这样区间左边在i和lf[i]之间就会加上1)
②从优先队列中取数,如果它的位置等于当前位置,那么就把队列中那个数的位置j处-1,在lf[j]-1处+1。
解释一下这个操作,还以上面那组数据为例,如果只是第一个操作的话,执行完以后的数列是这样的:
3 6 1 2 5 3
0 0 1 1
这样的话,当查询[2,4]时答案就不对了,这是由于这种操作只能保证之前的是正确的,这样就可能要把之前的操作“取消”,答案才会是正确的,因此,对于一个数,当操作到rn[i]+1的位置,就要把这个数之前的操作“取消”,也就是和①进行相反的操作。我用的优先队列存的右边要操作的位置,其实怎么搞都行,不一定要用优先队列,可以用vector存的,当时顺手写了个优先队列,所以……
③看懂第②歩,第三步就和明显了,把rn[i]+1加入优先队列。
之前用线段树写的,后来数据加强线段树就T了,然后想用vector代替优先队列,这样可以把优先队列那儿O(nlog(n))的复杂度变成O(n),结果MLE了……Orz,没办法,写了发树状数组1900ms+过掉了……果然树状数组比线段树快很多,也可能是我线段树写渣了。。。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=200000+10; int pre[maxn],num[maxn],ans[maxn]; int lf[maxn],rn[maxn]; int sum[maxn]; int n,m; struct Node { int l,pos; bool operator <(const Node &a) const { return l>a.l; } }; vector<int>vt[maxn]; vector<Node>querys[maxn]; int lowbit(int x) { return x&-x; } int Query(int x) { int ret=0; while(x>0) { ret+=sum[x]; x-=lowbit(x); } return ret; } void add(int x,int v) { while(x<=n) { sum[x]+=v; x+=lowbit(x); } } void solve() { memset(pre,0xff,sizeof(pre)); memset(sum,0,sizeof(sum)); int sz,ntmp,pp; for(int i=1;i<=n;++i) { sz=vt[num[i]].size(); pp=1; for(int j=0;j<sz;++j) { ntmp=vt[num[i]][j]; if(pre[ntmp]!=-1) pp=max(pp,pre[ntmp]+1); pre[ntmp]=i; } lf[i]=pp; } memset(pre,0xff,sizeof(pre)); for(int i=n;i>=1;--i) { sz=vt[num[i]].size(); pp=n; for(int j=0;j<sz;++j) { ntmp=vt[num[i]][j]; if(pre[ntmp]!=-1) pp=min(pp,pre[ntmp]-1); pre[ntmp]=i; } rn[i]=pp; } Node node,tmp; int x,y; priority_queue<Node>q; for(int i=1;i<=n;++i) { add(i,1); x=lf[i]-1; if(x) add(x,-1); while(!q.empty()) { tmp=q.top(); if(tmp.l==i) { q.pop(); add(tmp.pos,-1); x=lf[tmp.pos]-1; if(x) add(x,1); } else break; } y=rn[i]+1; if(y<=n) { tmp.l=y;tmp.pos=i; q.push(tmp); } sz=querys[i].size(); for(int j=0;j<sz;++j) { node=querys[i][j]; ans[node.pos]=Query(i)-Query(node.l-1); } } } int main() { //freopen("in.txt","r",stdin); for(int i=2;i<=200000;++i) for(int j=i;j<=200000;j+=i) vt[j].push_back(i); while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; for(int i=1;i<=n;++i) scanf("%d",&num[i]); for(int i=0;i<=n;++i) querys[i].clear(); int l,r; Node tmp; for(int i=0;i<m;++i) { scanf("%d%d",&l,&r); tmp.l=l;tmp.pos=i; querys[r].push_back(tmp); } solve(); for(int i=0;i<m;++i) printf("%d\n",ans[i]); } return 0; }