HDU 5869 Different GCD Subarray Query

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\n",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 }

 

posted @ 2018-10-09 10:07  MJT12044  阅读(163)  评论(0编辑  收藏  举报