hdu 4777 Rabbit Kingdom 离线+树状数组

题意:

给你n个数,然后询问m次,求出每次询问的区间内有多少个数是与该区间内其它数是互质的。

思路:

这题真的是做好久,这题的离线思想的确是犀利!一开始对铭神跟我讲的离线思想不太懂,后来看了qian99的解题报告才弄懂。
http://blog.csdn.net/qian99/article/details/14768235

数组lt[i], rt[i]。表示第i个数,左右两边距离i的最近的,与i不互质的下标。
具体看上面那份题解,我就不班门弄斧了。

总结:

主要卡在处理出lt, rt这两个数组。一开始是从2到sqrt(n)来枚举,把一个数的所有因子全部求出来,复杂度O(nsqrt(n)),TLE。
后来杰神教了O(n)筛选素数大法,以及把每个数的质因子求出来。根据唯一分解定理,每个大于1的自然数都可以写成质数的乘积。因此,两个数如果不是互质,那么他们至少有一个质因子是相同的。


预处理出每个数的质因子,保存在vecotr里面;再开个数组rd,每次都保存该质因子的最新下标即可。

往右扫一遍,往左扫一遍,lt,rt数组就出来了。
*这题加个快速读入收益很可观= =

code:

/* **********************************************
Created Time: 2014-10-23 19:19:51
File Name   : hdu4777.cpp
*********************************************** */
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cmath>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const int MAXN = 200100;
const int INF = 0x3f3f3f3f;
struct PP
{
        int l, r, rank;
        int ans;
}query[MAXN];
int lt[MAXN], rt[MAXN];
int rd[MAXN], a[MAXN];
int n, m;
bool Cmp(PP a, PP b)
{
        return a.r < b.r;
}
bool Cmp2(PP a, PP b)
{
        return a.rank < b.rank;
}
//datastruct
int c[MAXN];            //BIT
inline int Lowbit(int x)
{
        return x&(-x);
}
int Query(int x)
{
        int ret = 0;
        while(x > 0)
        {
                ret += c[x];
                x -= Lowbit(x);
        }
        return ret+c[0];
}
void Update(int x, int val)
{
        if(x == 0)
        {
                c[x] += val;
                return ;
        }
        while(x <= n)
        {
                c[x] += val;
                x += Lowbit(x);
        }
}
//
vector <int> ins[MAXN];
void Solve()
{
        //priority_queue <TI> myque;
        //memset(c, 0, sizeof(c));
        for(int i = 0;i <= n+1; i++)
                ins[i].clear();

        for(int i = 0;i <= n+5; i++)
                c[i] = 0;
        for(int i = 1, j = 1;i <= n; i++) //i: num; j : query;
        {
                Update(i, 1);
                Update(lt[i], -1);
                ins[rt[i]].push_back(i);
                //
                if(ins[i].size() > 0)
                {
                        for(int z = 0;z < ins[i].size(); z++)
                        {
                                int tt = ins[i][z];
                                Update(tt, -1);
                                Update(lt[tt], 1);
                        }
                }
                //
                while(query[j].r == i)
                {
                        PP &e = query[j];
                        e.ans = Query(e.r) - Query(e.l-1);
                        j++;
                }
        }
        //cout<<"c[0] = "<<c[0]<<endl;
}
inline int qin()
{
        char ch = getchar();
        int ret = 0;
        while(ch < '0' || ch > '9') ch = getchar();
        while(ch >= '0' && ch <= '9') 
        {
                ret = ret*10 + ch-'0';
                ch = getchar();
        }
        return ret;
}
const int P = MAXN;
int pri[P], pnum, mindiv[P];            //pri:save prime
bool vis[P];

void get_prime(int tt) {
    pnum = 0; vis[1] = 1;
    for(int i = 2;i <= tt; i++) {
        if(!vis[i]) {
            pri[pnum++] = i;
            mindiv[i] = i;
        }
        for(int j = 0;j < pnum; j++) {
                LL tmp = (LL)i*pri[j];
            if(tmp > tt)    break;
            vis[i*pri[j]] = 1;
            mindiv[i*pri[j]] = pri[j];
            if(i%pri[j] == 0)   break;
        }
    }
}
vector <int> pcur[MAXN];
void preDeal(int cur)
{
        int a = cur;
        if(pcur[cur].size() != 0)  return;
        while(cur > 1) {
                int tmp = mindiv[cur];
                pcur[a].push_back(tmp);
                while(cur%tmp == 0) cur /= tmp;
        }
}
int main()
{
        get_prime(MAXN);
        while(scanf("%d%d" ,&n, &m) != EOF)
        {
                if(n == 0 && m == 0) break;
                int valmax = 0;
                for(int i = 1;i <= MAXN; i++)
                        pcur[i].clear();
                for(int i = 1;i <= n; i++)
                {
                        a[i] = qin();
                        //scanf("%d", &a[i]);
                        preDeal(a[i]);
                        //valmax = max(a[i], valmax);
                }
                //left
                memset(rd, 0, sizeof(rd));
                for(int i = 1;i <= n; i++)
                {
                        //update
                        int pi = 0;
                        for(int j = 0;j < pcur[a[i]].size(); j++)
                        {
                                int tt = pcur[a[i]][j];
                                pi = max(pi, rd[tt]);
                                rd[tt] = i;
                        }
                        lt[i] = pi;
                }
                //right
                memset(rd, INF, sizeof(rd));
                for(int i = n;i >= 1; i--)
                {
                        int pi = n+1;
                        for(int j = 0;j < pcur[a[i]].size(); j++)
                        {
                                int tt = pcur[a[i]][j];
                                pi = min(pi, rd[tt]);
                                rd[tt] = i;
                        }
                        rt[i] = pi;
                }
                /*cout<<"test"<<endl;
                for(int i = 1;i <= n; i++)
                        cout<<lt[i]<<" "<<rt[i]<<endl;*/
                //query
                int l, r;
                for(int i = 1;i <= m; i++)
                {
                        l = qin();
                        r = qin();
                        //scanf("%d%d" ,&l ,&r);
                        query[i] = (PP){l ,r, i};
                }
                sort(query+1, query+m+1, Cmp);
                /*cout<<"test"<<endl;
                for(int i = 1;i <= m; i++)
                        cout<<query[i].r<<" ";
                puts("");
                */
                //
                Solve();
                sort(query+1, query+m+1, Cmp2);
                for(int i = 1;i <= m; i++)
                        printf("%d\n", query[i].ans);
        }
        return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值