Different GCD Subarray Query
http://acm.hdu.edu.cn/showproblem.php?pid=5869
分析:
st表+gcd+二分+树状数组。
调的心累。
从一个点为右端点,往左扩展,gcd是单调下降的。而且下降次数不超过log次。于是可以用st表预处理,做到O(1)求区间的gcd。然后二分断点处即可。
求区间的不同gcd的个数:离线,枚举右端点,考虑计算所有以这个点为右端点的答案,树状数组维护。注意到相同的gcd只会算一次,用last维护上一个出现的位置,这个gcd最右边的位置会替代了左边的所有的位置,只在最右边的gcd的位置加入一个1即可。
后来在看了几篇博客,发现其实不需要二分!!!直接往左扫过去,如果gcd=1了,就break,而且比二分还快!!!(gcd减少次数本来就不超过log次,可能是数据比较随机的情况下,很快就变成1了。。。)
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 #define fi(s) freopen(s,"r",stdin); 12 #define fo(s) freopen(s,"w",stdout); 13 using namespace std; 14 typedef long long LL; 15 16 inline int read() { 17 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 18 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 19 } 20 21 const int N = 100005; 22 23 struct Que{ 24 int l, r, id; 25 bool operator < (const Que &A) const { 26 return r < A.r; 27 } 28 }q[N]; 29 struct Bit{ 30 int n;LL sum[N]; 31 void Clear() { memset(sum, 0, sizeof(sum)); } 32 void update(int p,int v) { 33 for (; p<=n; p+=(p&(-p))) sum[p] += v; 34 } 35 LL query(int p) { 36 LL ans = 0; 37 for (; p; p-=(p&(-p))) ans += sum[p]; 38 return ans; 39 } 40 }bit; 41 int a[N], f[N][20], last[N * 10], Log[N]; // a[i]的范围1e6!!! 42 LL ans[N]; 43 int n, Q; 44 45 int gcd(int a,int b) { 46 return b == 0 ? a : gcd(b, a % b); 47 } 48 void init() { 49 memset(ans, 0, sizeof(ans)); 50 memset(last, 0, sizeof(last)); 51 bit.Clear(); bit.n = n; 52 for (int i=1; i<=n; ++i) f[i][0] = a[i]; 53 for (int j=1; j<=Log[n]; ++j) 54 for (int i=1; (i+(1<<j)-1)<=n; ++i) 55 f[i][j] = gcd(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); 56 } 57 int Gcd(int l,int r) { 58 int t = Log[r - l + 1]; 59 return gcd(f[l][t], f[r - (1 << t) + 1][t]); 60 } 61 int find(int l,int r,int d,int R) { // R! R! R! not r! r! r! 62 int ans = 0; 63 while (l <= r) { 64 int mid = (l + r) >> 1; 65 if (Gcd(mid, R) == d) ans = mid, r = mid - 1; 66 else l = mid + 1; 67 } 68 return ans - 1; 69 } 70 void solve() { 71 sort(q + 1, q + Q + 1); 72 int now = 1; 73 for (int i=1; i<=n; ++i) { 74 int p = i, d = a[i]; 75 while (p) { 76 if (!last[d]) bit.update(p, 1); 77 else if (last[d] < p) bit.update(last[d], -1), bit.update(p, 1); 78 last[d] = p; 79 p = find(1, p, d, i); 80 if (p) d = Gcd(p, i); 81 } 82 // for (int j=i; j; --j,d=Gcd(j,i)) { 83 // if (j > last[d]) { 84 // if (last[d]) bit.update(last[d], -1); 85 // bit.update(j, 1); 86 // last[d] = j; 87 // } 88 // if (d == 1) break; 89 // } 90 while (now <= Q && q[now].r == i) { 91 ans[q[now].id] = bit.query(q[now].r) - bit.query(q[now].l - 1); 92 now ++; 93 } 94 } 95 for (int i=1; i<=Q; ++i) printf("%lld ",ans[i]); 96 } 97 int main() { 98 Log[0] = -1; 99 for (int i=1; i<=100000; ++i) Log[i] = Log[i >> 1] + 1; 100 while (~scanf("%d%d", &n, &Q)) { 101 for (int i=1; i<=n; ++i) a[i] = read(); 102 init(); 103 for (int i=1; i<=Q; ++i) 104 q[i].l = read(), q[i].r = read(), q[i].id = i; 105 solve(); 106 } 107 return 0; 108 }