HYSBZ 2038 小Z的袜子(hose) (莫队算法)

简单说一下莫队算法的复杂度,莫队算法其实是在区间的进退处理上进行了一个优化,大大降低复杂度,首先是区间的分块处理,将数据分为 n 个块,考虑左边界的移动情况,由于每个块中每个询问左边界最多移动 n 步,所以左边界的复杂度为 mn ,再考虑右边界的移动情况,由于块中右边界保持升序,所以一个块中右边界的移动复杂度为 n ,考虑块与块之间的移动情况,最多为n步,所以右边界移动的复杂度为 nn ,再加上统计color的复杂度为 O1 ,所以整体复杂度为 m+nn

#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");

using namespace std;

#define INF 0x3f3f3f3f
#define maxn 100005

struct node
{
    int l, r;
    int id;
} q[maxn];

int vis[maxn];
int block[maxn];
int col[maxn];
int ans1[maxn],ans2[maxn];
int a,b;

bool cmp(node A,node B)
{
    if(block[A.l]==block[B.l]) return A.r<B.r;
    return block[A.l]<block[B.l];
}

void update(int add,int pos)
{
    if(add==1) a+=vis[pos],vis[pos]++;
    else a-=vis[pos]-1,vis[pos]--;
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(vis,0,sizeof vis);
        int bk=ceil(sqrt(n*1.0));
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&col[i]);
            block[i]=i/bk;
        }
        block[n+1]=block[n]+1;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id=i;
        }
        sort(q,q+m,cmp);
        int l=0,r=1;
        a=0,b=0;
        for(int i=0; i<m; i++)
        {
            if(q[i].r-q[i].l==0)
            {
                ans1[q[i].id]=0;
                ans2[q[i].id]=1;
                continue;
            }
            for(;r<=q[i].r;r++) update(1,col[r]);
            for(;r-1>q[i].r;r--) update(-1,col[r-1]);
            for(;l+1<q[i].l;l++) update(-1,col[l+1]);
            for(;l>=q[i].l;l--) update(1,col[l]);
            ans1[q[i].id]=a;
            b=q[i].r-q[i].l+1;
            if(b%2==0) ans2[q[i].id]=b/2*(b-1);
            else ans2[q[i].id]=(b-1)/2*b;
        }
        for(int i=0; i<m; i++)
        {
            int temp=__gcd(ans1[i],ans2[i]);
            ans1[i]/=temp;
            ans2[i]/=temp;
            if(ans1[i]==0) ans2[i]=1;
            printf("%d/%d\n",ans1[i],ans2[i]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值