标签:hdu
题意:
给出m个区间查询,查询 区间里和区间中的其他数字 都互质 的数字的个数
思路:
简单题,因为并没有 修改,全是查询
把所有查询读入,按照左端点 从左往右来处理。(原因稍后
首先预处理对于每一个位置(id)的数字,往左和往右最远到哪个位置,会出现和这个数字不互质的数字,用l[id]和r[id]保存下来。同时用邻接表(因为这么处理比较简单)保存下来对于一个位置iid,有哪个数字,它的“不互质区间”左端点是iid。——其实我感觉这个预处理过程,用到了素数打表,整数质分界,和我以前不知道的处理方法,比主算法还要难...sigh
然后就是用树状数组处理了。我们从数组最左端开始,每处理到一个位置id,这个位置右边的所有数字,就不用再考虑当前这个数字的影响了。所以我们就可以把所有L[x]=id的位置x 的count + 1,然后R[x]的count - 1。 同时我们应该把R[id]的count+1(因为我们之前给x的count+1的时候,曾经把R[x]的count减成了-1)
我也知道我写的不好理解...但是就是很明确却不大容易想到...:)
你来想,对于按照左端点从小到大排完序的所有区间,每次处理到区间左端点左边的那个位置时,当前区间和就是答案!真是好~
code:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<string> #include<queue> #include<map> #include<set> #include<cmath> #include<cstdlib> using namespace std; #define INF 0x3f3f3f3f #define PI acos(-1.0) #define mem(a, b) memset(a, b, sizeof(a)) #define mod 1000000007 typedef pair<int,int> pii; typedef long long LL; //------------------------------ const int maxn = 200005; struct node{ int s, e, id; bool operator < (const node nt) const{ if(s != nt.s) return s < nt.s; else return e < nt.e; } }q[maxn]; int n, m; int a[maxn]; struct BIT{ int C[maxn]; void init(){ memset(C, 0, sizeof(C)); } int lowbit(int x){ return -x&x; } int sum(int x){ int ret = 0; while(x > 0){ ret += C[x]; x -= lowbit(x); } return ret; } void add(int x,int v){ while(x <= n){///这个地方的n是要根据C[]数组需要保存的范围来确定的,不一定就是n C[x] += v; x += lowbit(x); } } }bit; int vis[maxn], prime[maxn], pcnt = 0; void getprime(){ memset(vis, 0, sizeof(vis)); for(long long i = 2; i < maxn; i++){ if(!vis[i]){ prime[pcnt++] = i; for(long long j = i*i; j < maxn; j+=i){ vis[j] = 1; } } } } vector<int> g[maxn]; void getfac(int id){ g[id].clear(); int tmp; scanf("%d",&tmp); for(int i = 0; i < pcnt && prime[i] * prime[i] <= tmp; i++){ if(tmp % prime[i] == 0){ g[id].push_back(prime[i]); while(tmp % prime[i] == 0) tmp /= prime[i]; } } if(tmp != 1) g[id].push_back(tmp); } int l[maxn], r[maxn], pos[maxn];//pos中存的是每个素因子出现的最靠右(左)的位置 vector<int> vec[maxn]; void deal(){ memset(pos, 0, sizeof(pos)); for(int i = 0; i < maxn; i++) vec[i].clear(); for(int i = 1; i <= n; i++){ getfac(i); l[i] = 1; for(int j = 0; j < g[i].size(); j++){ int tmp = g[i][j]; l[i] = max(l[i], pos[tmp]+1);//这个地方求出的其实是最左端的互质的位置 pos[tmp] = i; } l[i]--;//所以这里位置往左移一个 vec[l[i]].push_back(i); } memset(pos, INF, sizeof(pos)); for(int i = n; i >= 1; i--){ r[i] = n; for(int j = 0; j < g[i].size(); j++){ int tmp = g[i][j]; r[i] = min(r[i], pos[tmp]-1); pos[tmp] = i; } r[i]++; } } void init(){ deal(); int s, e; for(int i = 0; i < m; i++){ scanf("%d%d",&s,&e); q[i].id = i; q[i].s = s; q[i].e = e; } } int ans[maxn]; void solve(){ sort(q, q+m); int left = 1; // for(int i = 1; i <= n; i++){ // printf("left = %d right = %d\n",l[i],r[i]); // } // for(int i = 1; i <= n; i ++){ // printf("=== %d : \n",i); // for(int j = 0; j < vec[i].size(); j++){ // printf("%d ",vec[i][j]); // } // if(vec[i].size() != 0) // printf("\n"); // } bit.init(); for(int i = 1; i <= n; i++){ if(l[i] < 1){ bit.add(i,1); if (r[i] <= n) bit.add(r[i], -1); } } for(int i = 0; i < m; i++){ while(left < q[i].s){ // bit.add(left, -1);//这个地方加不加无所谓,因为以后再也用不到left位置的值了 if (r[left] <= n) bit.add(r[left], 1); for(int j = 0; j < vec[left].size(); j++){ int k = vec[left][j]; bit.add(k, 1); if (r[k] <= n) bit.add(r[k], -1); } left++; } ans[q[i].id] = bit.sum(q[i].e) - bit.sum(q[i].s-1); } for(int i = 0; i < m; i++){ printf("%d\n",ans[i]); } } int main(){ getprime(); while(scanf("%d%d",&n,&m) != EOF){ init(); solve(); } return 0; } /* 10 2 2 3 4 5 6 7 8 9 10 11 */
标签:hdu
原文地址:http://blog.csdn.net/u013382399/article/details/45768285