hdu4777-Rabbit Kingdom

题意:求区间内与其他任何数都互质的数的个数。

题解:求出每个数左右互质的边界。然后对询问排序,通过树状数组求解。

讲道理真的好难啊= =

http://blog.csdn.net/dyx404514/article/details/15507209 这个博客讲的最清楚(竟然是戴神的博客=。= 听过戴神讲splay,现在还不会……

#include <bits/stdc++.h>

using namespace std;

const int N = 200005;

/***素数打表***/
int p[N];
int is_p[N+1];
int cnt_p;
void get_p() {
    for (int i = 0; i <= N; ++i) is_p[i] = 1;
    cnt_p = is_p[0] = is_p[1] = 0;
    for (int i = 2; i <= N; ++i) {
        if (is_p[i]) {
            p[cnt_p++] = i;
            for (int j = i * 2; j <= N; j += i) is_p[j] = 0;
        }
    }
}
/***因数分解***/
int fac[N];     // 记录出现的因数
int cal_fac(int x) {
    int tmp = x;
    int idx = 0;
    int i;
    for (i = 0; p[i] <= tmp/p[i]; ++i) {
        if (tmp%p[i]) continue;
        while (tmp%p[i] == 0) tmp /= p[i];
        fac[idx++] = p[i];
    }
    if (tmp != 1) fac[idx++] = tmp;
    return idx;
}
/***计算每个数互质的最左最右区间***/
int l[N], r[N];
int adj[N];
int a[N];
void cal_inv(int n) {
    for (int i = 0; i < N; ++i) adj[i] = 0;
    for (int i = 1; i <= n; ++i) {
        int cnt = cal_fac(a[i]);
        l[i] = 0;
        for (int j = 0; j < cnt; ++j) {
            l[i] = max(l[i], adj[fac[j]]);
            adj[fac[j]] = i;
        }
    }
    for (int i = 0; i < N; ++i) adj[i] = n+1;
    for (int i = n; i >= 1; --i) {
        r[i] = n+1;
        int cnt = cal_fac(a[i]);
        for (int j = 0; j < cnt; ++j) {
            r[i] = min(r[i], adj[fac[j]]);
            adj[fac[j]] = i;
        }
    }
}

struct node {
    int l, r, id;
    bool operator<(const node x) const { return l < x.l; }
} qry[N];

int bit[N];
int lowbit(int x) { return x&-x; }
void add(int x, int v, int n) { while(x<=n) bit[x]+=v,x+=lowbit(x); }
int sum(int x) { int ans=0; while(x) ans+=bit[x],x-=lowbit(x); return ans; }

vector<int> lb[N]; // lb[i] 以i为左边界的数
int ans[N];
int main() {
//freopen("in.txt", "r", stdin);
    get_p();
    int n, k;
    while (~scanf("%d%d", &n, &k)) {
        if (n == 0) break;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", a+i);
        }
        cal_inv(n);

        for (int i = 0; i < k; ++i) {
            scanf("%d%d", &qry[i].l, &qry[i].r);
            qry[i].id = i;
        }
        sort(qry, qry+k);
        for (int i = 0; i <= n; ++i) lb[i].clear();
        memset(bit, 0, sizeof bit);
        for (int i = 1; i <= n; ++i) {
            if (!l[i]) { add(i, 1, n); add(r[i], -1, n); }
            else lb[l[i]].push_back(i);
        }
        int pos = 1;
        for (int i = 0; i < k; ++i) {
            while (qry[i].l > pos) {
                add(pos, -1, n);
                add(r[pos], 1, n);
                for (unsigned j = 0; j < lb[pos].size(); ++j) {
                    int x = lb[pos][j];
                    add(x, 1, n);
                    add(r[x], -1, n);
                }
                pos++;
            }
            ans[qry[i].id] = sum(qry[i].r)-sum(qry[i].l-1);
        }
        for (int i = 0; i < k; ++i) {
            printf("%d\n", ans[i]);
        }
    }

    return 0;
}
时间: 2024-10-06 03:52:33

hdu4777-Rabbit Kingdom的相关文章

HDU-4777 Rabbit Kingdom(区间更新求和)

题目大意:给一个n个整数的数列,q次询问,每次询问区间[l,r]中与区间中其它数互质的数的个数.. 题目分析:离线处理,这里以询问区间的左端点从小到大的顺序为例.为了叙述方便,用f(l,r)表示区间[l,r]中与区间中其它数互质的数的个数..每次用线段树或树状数组维护以 a(i)(1<=i<=n) 为左端点的所有区间的 f 值的前缀和.左端点从1~n,每变化一次,便做一次更新操作.这样,f(l,r)=sum(l)-sum(r+1).对于数列中的每个元素a(i),预处理出其左边第一个不与他互质的

hdu4777 Rabbit Kingdom 树状数组+区间操作+素数打表

题目大意:给N个数,有M个查询,问区间[L,R]之间有多少个数与这个区间内的其他数都互质. 思路:dp显然很难搞,既然是求区间就试试每一个数最大可以对答案产生贡献的区间,即预处理出一个数在(lp,rp)内始终与其他数互质的最大区间 则lp和rp分别为左边和右边第一个与他不互质的数的位置 处理的时候素数打表然后从左到右始终更新对于某一个素因子出现的最右的位置然后更新l,r,可以做到 然后就是把查询按l从小到大排序,这样的话每处理一个新的查询,对于在这个查询的 l 左边的数就可以不用考虑了 然后我们

13杭州区域赛现场赛Rabbit Kingdom(树状数组+离线)

题意:给你一个长度数列,再给你m个询问(一个区间),问你在这个区间里面有多少个数与其他的数都互质. 解题思路:你看这种类型的题目都可以肯定这是 离线+树状数组(线段树).主要就是他的更新信息.这里我的处理是先把1-200000(每个数的范围)数里面所有的质因子求出来.然后从后往前遍历数组.会出现以下几种情况 1.a[k]的质因子在后面出现过而[更新标记] 和[被更新标记] 都为假 2.a[k]的质因子在后面出现过的那个位置 I   [更新标记]为 真 . 3.a[k]的质因子在后面出现过且那个位

hdu 4777 Rabbit Kingdom(离线树状数组&amp;思维)

Rabbit Kingdom Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 964    Accepted Submission(s): 315 Problem Description Long long ago, there was an ancient rabbit kingdom in the forest. Every rab

hdu 4777 Rabbit Kingdom(树状数组)

题目链接:hdu 4777 Rabbit Kingdom 题目大意:一个兔子王国,有N只兔子,每只兔子有一个重量,如果两只兔子的重量不互质,那么就会干架,现在国王想将l r之间的兔子关进监狱,它想知道会有多少只兔子不会和别的兔子干架. 解题思路:预处理出每只兔子的L,R表示向左和向右最近会与该兔子发生冲突的兔子,预处理的时候只要将每只兔子的重量分解成质因子后遍历两遍. 对于询问,将询问按照右区间排序,碰到i,则L位置+1,碰到R,则i位置+1,L位置-1.(如果L ≤ l && r ≤ R

HDU 4777 Rabbit Kingdom(树状数组)

HDU 4777 Rabbit Kingdom 题目链接 题意:给定一些序列,每次询问一个区间,求出这个区间和其他数字都互质的数的个数 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int INF = 0x3f3f3f3f; typedef long long ll; const ll N = 200

hdu 4778 Rabbit Kingdom(状态压缩)

题目链接:hdu 4778 Rabbit Kingdom 题目大意:Alice和Bob玩游戏,有一个炉子,可以将S个相同颜色的宝石换成一个魔法石,现在有B个包,每个包里有若干个宝石,给出宝石的颜色.现在由Alice开始,两人轮流选取一个包的宝石放入炉中,每当获得一个魔法石时,可以额外获得一次机会再选一个包放入.两人均按照自己的最优策略,问说最后Alice的魔法石-Bob的魔法石是多少. 解题思路:状态压缩,221,对于每次移动到下一个状态,如果获得的魔法石g非零,则说明下一个状态还是自己在取,则

HDU 4777 Rabbit Kingdom

素因子分解,树状数组.$ACM/ICPC$ $2013$杭州区域赛$H$题. 首先需要处理出数字$a[i]$左边最远到$L[i]$,右边最远到$R[i]$区间内所有数字都与$a[i]$互质. 那么对于左端点在$[L[i],i]$并且右端点在$[i,R[i]]$的询问,$a[i]$就可以作出一个贡献. 接下来的问题就可以转化为二维平面上有很多矩形,每次询问一个点被多少矩形覆盖.可以离线操作,类似于扫描线的思想做就可以了. 素因子分解需要一开始把$20$万个数字都处理好,避免每组测试数据内重复处理.

hdu 4777 Rabbit Kingdom (离线树状数组)

题目大意: 给出m个查询,查询出[ l - r] 之间去 这个区间所有的数都互质的数有多少个. 思路分析: 首先我们处理出来每一个位置,左边和右边第一个与之不互质的数的位置.记在pre 和 next下.这个方法用分解质因数就好. 一个区间内的答案,等于这个区间的所有数减去有与之互质数的个数. 现在要统计的就是 1.对于一个给定的查询[l,r] 区间,统计有多少个 i (l<= i  <=r) 的pre[i] 或 next[i]在[l,r]内. 2.对于一个给定的查询[l,r]区间,统计有多个个

HDU 4777 Rabbit Kingdom --容斥原理+树状数组

题意: 给一个数的序列,询问一些区间,问区间内与区间其他所有的数都互质的数有多少个. 解法: 直接搞有点难, 所谓正难则反,我们求区间内与其他随便某个数不互质的数有多少个,然后区间长度减去它就是答案了. 那么怎么求区间内与区间其他某个数不互质的数的个数(记为cnt)呢? 我们用L[i],R[i]表示在整个序列中左边与 i 最近的与 i 不互质的数的位置,R[i]表示右边的,L[i],R[i]我们可以正反扫一遍顺便分解因子,用个pos[]记录很方便地求出.那么区间内的cnt为L[i]或R[i]在区