bzoj 2038 莫队入门

http://www.lydsy.com/JudgeOnline/problem.php?id=2038

题意:多次询问区间内取出两个相同颜色的种类数

思路:由于不是在线更新,那么可以进行离线查询,而且当知道了[l,r]的答案,且能在O(1)的条件下得知[l-1,r],[l+1,r],[l,r+1],[l,r-1]的答案,那么就能使用莫队算法了。 大致上,将区间分块,由于n=a+b>=a*b,显然将区间开平方根是最优的,我们先将询问保存,按照块序第一优先,再考虑右端点进行排序。再来,使用cnt[]来记录当前颜色出现的次数,当得到[l,r]后,再考虑加入[l-1,r] ,[l,r+1],对答案\(ans-=cnt[col[l-1]]^2,ans+=(cnt[[col[l-1]]+1)^2 \)如果是缩小区间,那么反之。

/** @Date    : 2016-12-07-21.28
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version :
  */

#include<bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

LL col[N];
int blc[N];
int cnt[N];
struct yuu
{
    LL l, r;
    int id;
    LL a, b;
}q[N];

int cmp(yuu a, yuu b)
{
    if(blc[a.l] == blc[b.l])
        return a.r < b.r;
    return a.l < b.l;
}

int cmpi(yuu a, yuu b)
{
    return a.id < b.id;
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    //{
        MMF(cnt);
        for(int i = 1; i <= n; i++)
            scanf("%lld", col + i);
        int ct = sqrt(n);
        for(int i = 1; i <= n; i++)//分块
            blc[i] = (i - 1)/ct + 1;

        for(int i = 1; i <= m; i++)
        {
            scanf("%lld%lld", &q[i].l, &q[i].r);
            q[i].id = i;
        }
        sort(q + 1, q + 1 + m, cmp);
        LL ans = 0;
        LL ll = 1, rr = 0;
        for(int i = 1; i <= m; i++)
        {
            //cout << q[i].l << q[i].r << endl;
            if(ll > q[i].l)
                for(int j = ll; j > q[i].l; j--)
                    ans += (2*cnt[col[j - 1]] + 1), cnt[col[j - 1]]++;
            if(ll < q[i].l)
                for(int j = ll; j < q[i].l; j++)
                    ans -= (2*cnt[col[j]] - 1), cnt[col[j]]--;
            if(rr < q[i].r)
                for(int j = rr; j < q[i].r; j++)
                    ans += (2*cnt[col[j + 1]] + 1), cnt[col[j + 1]]++;
            if(rr > q[i].r)
                for(int j = rr; j > q[i].r; j--)
                    ans -= (2*cnt[col[j]] - 1), cnt[col[j]]--;
            ll = q[i].l;
            rr = q[i].r;
            if(q[i].l == q[i].r)
            {
                q[i].a = 0;
                q[i].b = 1;
                continue;
            }
            q[i].b = (q[i].r - q[i].l) * (q[i].r - q[i].l + 1);
            q[i].a = ans - (q[i].r - q[i].l + 1);
            LL g = __gcd(q[i].b, q[i].a);
            //cout << ans <<endl;
            q[i].a /= g;
            q[i].b /= g;
        }
        sort(q + 1, q + 1 + m, cmpi);
        for(int i = 1; i <= m; i++)
            printf("%lld/%lld\n", q[i].a, q[i].b);
    //}
    return 0;
}
时间: 2025-01-14 08:55:59

bzoj 2038 莫队入门的相关文章

莫队入门

本文转自大米饼,略加修改 ·排序巧妙优化复杂度,带来NOIP前的最后一丝宁静.几个活蹦乱跳的指针的跳跃次数,决定着莫队算法的优劣…… ·目前的题型概括为三种:普通莫队,树形莫队以及带修莫队. 若谈及入门,那么BZOJ2038的美妙袜子一题堪称顶尖. [例题一]袜子 ·述大意:      进行区间询问[l,r],输出该区间内随机抽两次抽到相同颜色袜子的概率. ·分析:      首先考虑对于一个长度为n区间内的答案如何求解.题目要求Ans使用最简分数表示:那么分母就是n*n(表示两两袜子之间的随机

bzoj 3289 莫队 逆序对

莫队维护逆序对,区间左右增减要分类讨论. 记得离散化. 1 /************************************************************** 2 Problem: 3289 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:5480 ms 7 Memory:3164 kb 8 ********************************************************

bzoj 3809 莫队

收获: 1.分块时顺便记录每个位置所属的块,然后一次排序就OK了. 2.要权衡在“区间移动”与“查询结果”之间的时间,莫队算法一般区间移动频率远大于查询结果,所以我们选择的辅助数据结构时就要注意了,我最开始写的是值域线段树,自己生成的极限数据要1m8s,改成树状数组后要24s,还是过不了,hzwer只要13s,细看hzwer的代码,发现Ta用的是分块,O(1)修改O(n0.5)查询,改成分块后的确快多了. 3.块的大小理论最优值是O(n*m-0.5),最开始设成这个交上去35卡过,改成hzwer

BZOJ 3339 &amp; 莫队+&quot;所谓的暴力&quot;

题意: 给一段数字序列,求一段区间内未出现的最小自然数. SOL: 框架显然用莫队.因为它兹瓷离线. 然而在统计上我打了线段树...用&维护的结点...400w的线段树...然后二分查找...炸的妥妥的... 然后发现所谓的"暴力"...直接开数组维护...因为指针具有一定的单调性,一次更改可以直接得到解,不用每次都查询... woc真是...有时候数据结构用多了忽略了那些更简单更实用的方法... Code TLE的代码: /*=========================

2038: [2009国家集训队]小Z的袜子(hose)+莫队入门

题目链接:2038: [2009国家集训队]小Z的袜子(hose) 题目: Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬.你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子

HYSBZ 2038 莫队算法

小Z的袜子(hose) Time Limit:20000MS     Memory Limit:265216KB     64bit IO Format:%lld & %llu Submit Status Practice HYSBZ 2038 Appoint description:  System Crawler  (2016-07-13) Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程

BZOJ 3339 &amp;&amp; BZOJ 3585 莫队+权值分块

显然若一个数大于n就不可能是答案. 1 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <algorithm> 6 #include <map> 7 #include <cmath> 8 using namespace std; 9 const int Maxn=200010; 10 struct Info{int l,r,Id;}P[

BZOJ 4810 莫队+bitset

思路: 看完这道题根本没有思路啊.... 然后我就膜拜了一波题解... 这神tm乱搞思路 维护两个bitset 第一个bitset代表当前区间哪些数出现过 第二个bitset是 maxp-p出现过 差为x的时候  就用第一个bitset与一下它右移x就好了 和为x的时候 就第一个bitset与一下第二个bitset右移maxp-x 乘积为x的时候 就枚举约数,, 暴力判断一下 复杂度是O(nsqrt(n)+n^2/32)的 //By SiriusRen #include <cmath> #in

P2709 小B的询问 【普通莫队】

这是我的莫队入门题,我也了解到了莫队分为普通莫队以及带修莫队.顾名思义,普通莫队不需要修改区间的值,而带修莫队处理区间的值会修改的查询. 能用莫队的前提条件: 1.在知道 [l, r]中信息时,可以在 O(1)的复杂度内知道 [l - 1, r],[l + 1, r],[l, r - 1],[l, r + 1]的信息,否则复杂度会爆炸. 2.能离线处理. 莫队的时间复杂度为O(n ^ 1.5),但实际效果一定会优于这个时间复杂度. 莫队的主要操作: 1.对查询区间,以 left 来进行分块,然后