题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2038

就是莫队算法;

先写了个分块,惨WA:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=;
int n,m,K,c[maxn],rk[maxn],cnt[maxn],cnt2[maxn],ct=,t,tmp[maxn];
ll sum,s;
struct N{int l,r;ll ans,ans2;}q[maxn];
int rd()
{
int ret=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return ret;
}
bool cmp(int x,int y){return q[x].l<q[y].l;}
bool cmp2(int x,int y){return q[x].r<q[y].r;}
int C(int x){return x*(x-)/;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void yf(N &x)//&
{
ll k=gcd(x.ans2,x.ans);
x.ans/=k;x.ans2/=k;
}
void solve(int k)
{
sort(tmp+,tmp+t+,cmp2);
sum=;
memset(cnt,,sizeof cnt);
int L=k*K,R=L+;
for(int i=;i<=t;i++)
{
memset(cnt2,,sizeof cnt2);
while(R<=q[tmp[i]].r)
{
sum+=cnt[c[R]];cnt[c[R]]++;R++;
}
s=sum;
for(int j=L;j>=q[tmp[i]].l;j--)
{
s+=cnt[c[j]]+cnt2[c[j]];cnt2[c[j]]++;
}
q[tmp[i]].ans=s;
q[tmp[i]].ans2=C(q[tmp[i]].r-q[tmp[i]].l+);
yf(q[tmp[i]]);
}
}
int main()
{
n=rd();m=rd();K=sqrt(n);
for(int i=;i<=n;i++)c[i]=rd();
for(int i=;i<=m;i++)q[i].l=rd(),q[i].r=rd(),rk[i]=i;
sort(rk+,rk+m+,cmp);
for(int i=;(i-)*K<n;i++)
{
t=;
while(q[rk[ct]].l<=i*K&&ct<=m)tmp[++t]=rk[ct],ct++;
solve(i);
}
for(int i=;i<=m;i++)
printf("%lld/%lld\n",q[i].ans,q[i].ans2);
return ;
}

然后看了看题解,竟然是另一种做法,处理了一下式子:https://www.cnblogs.com/MashiroSky/p/5914637.html

所以抄了一下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=;
int n,m,K,c[maxn],cnt[maxn],blk[maxn];
ll ans;
struct N{int l,r,bh;ll a,b;}q[maxn];
int rd()
{
int ret=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return ret;
}
bool cmp(N x,N y){return blk[x.l]==blk[y.l]?x.r<y.r:blk[x.l]<blk[y.l];}
bool cmp2(N x,N y){return x.bh<y.bh;}
ll gcd(ll a,ll b){return a%b==?b:gcd(b,a%b);}
void update(int x,int val)
{
ans-=cnt[c[x]]*cnt[c[x]];
cnt[c[x]]+=val;
ans+=cnt[c[x]]*cnt[c[x]];
}
int main()
{
n=rd();m=rd();K=sqrt(n);
for(int i=;i<=n;i++)c[i]=rd(),blk[i]=(i-)/K+;;
for(int i=;i<=m;i++)q[i].l=rd(),q[i].r=rd(),q[i].bh=i;
sort(q+,q+m+,cmp);
for(int i=,l=,r=;i<=m;i++)
{
while(l<q[i].l)update(l,-),l++; while(l>q[i].l)update(l-,),l--;
while(r<q[i].r)update(r+,),r++; while(r>q[i].r)update(r,-),r--;
if(q[i].l==q[i].r)
{
q[i].a=;q[i].b=;continue;
}
q[i].a=(ll)ans-(r-l+); q[i].b=(ll)(r-l+)*(r-l);//(ll)!!!
ll k=gcd(q[i].a,q[i].b);//把分子放前面,万一分子是0
q[i].a/=k; q[i].b/=k;
}
sort(q+,q+m+,cmp2);
for(int i=;i<=m;i++)
printf("%lld/%lld\n",q[i].a,q[i].b);
return ;
}

...

然后又看到一篇博客:https://www.cnblogs.com/xuwangzihao/p/5199174.html

我的想法还是可以的嘛,加入一个点就是增加了之前有的这种点个数那么多的点对,所以维护点的个数即可;

主要是这个题不用严格按照分块来做,只是按分块排一下序就可以保证时间复杂度了,所以 l 和 r 直接全局移动就可以;

这样的话代码突然变得好优美...说到底自己那样的分块还是写得太丑,都不能保证正确呢...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=;
int n,m,K,c[maxn],cnt[maxn],blk[maxn];
ll ans;
struct N{int l,r,bh;ll a,b;}q[maxn];
int rd()
{
int ret=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return ret;
}
bool cmp(N x,N y){return blk[x.l]==blk[y.l]?x.r<y.r:blk[x.l]<blk[y.l];}
bool cmp2(N x,N y){return x.bh<y.bh;}
ll C(ll x){return x*(x-)/;}
ll gcd(ll a,ll b){return a%b==?b:gcd(b,a%b);}
void pop(int x){cnt[c[x]]--;ans-=cnt[c[x]];}//注意顺序
void push(int x){ans+=cnt[c[x]];cnt[c[x]]++;}
int main()
{
n=rd();m=rd();K=sqrt(n);
for(int i=;i<=n;i++)c[i]=rd(),blk[i]=(i-)/K+;
for(int i=;i<=m;i++)q[i].l=rd(),q[i].r=rd(),q[i].bh=i;
sort(q+,q+m+,cmp);
for(int i=,l=,r=;i<=m;i++)
{
while(l<q[i].l)pop(l),l++;
while(l>q[i].l)push(l-),l--;
while(r<q[i].r)push(r+),r++;
while(r>q[i].r)pop(r),r--;
q[i].a=ans;
q[i].b=C(r-l+);
ll k=gcd(q[i].a,q[i].b);//把分子放前面,万一分子是0
q[i].a/=k; q[i].b/=k;
}
sort(q+,q+m+,cmp2);
for(int i=;i<=m;i++)
printf("%lld/%lld\n",q[i].a,q[i].b);
return ;
}

bzoj2038 小Z的袜子(hose)——莫队算法的更多相关文章

  1. BZOJ2038: [2009国家集训队]小Z的袜子(hose) -- 莫队算法 ,,分块

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 3577  Solved: 1652[Subm ...

  2. [BZOJ2038] [2009国家集训队]小Z的袜子(hose) 莫队算法练习

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 10299  Solved: 4685[Sub ...

  3. BZOJ2038 小Z的袜子 (莫队算法)

    题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=2038 专题练习: http://acm.hust.edu.cn/vjudge/conte ...

  4. BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7687  Solved: 3516[Subm ...

  5. kyeremal-bzoj2038-[2009国家集训队]-小z的袜子(hose)-莫队算法

    id=2038">bzoj2038-[2009国家集训队]-小z的袜子(hose) F.A.Qs Home Discuss ProblemSet Status Ranklist Con ...

  6. 【bzoj2038】[2009国家集训队]小Z的袜子(hose) 莫队算法

    原文地址:http://www.cnblogs.com/GXZlegend/p/6803860.html 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终 ...

  7. [bzoj2038][2009国家集训队]小Z的袜子(hose)——莫队算法

    Brief Description 给定一个序列,您需要处理m个询问,每个询问形如[l,r],您需要回答在区间[l,r]中任意选取两个数相同的概率. Algorithm Design 莫队算法入门题目 ...

  8. BZOJ2038: [2009国家集训队]小Z的袜子(hose) 莫队算法

    要使用莫队算法前提 ,已知[l,r]的答案,要能在logn或者O(1)的时间得到[l+1,r],[l-1,r],[l,r-1],[l,r+1],适用于一类不修改的查询 优美的替代品——分块将n个数分成 ...

  9. Bzoj 2038---[2009国家集训队]小Z的袜子(hose) 莫队算法

    题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=2038 Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色 ...

随机推荐

  1. E题

    题目大意: 找到一个最小的l值,使得a到b-l+1中任取一个数开始前进l次,中间包含至少有k个素数,如果找不到,返回-1: 运用素数打表法和2分法便能简单搞定: 题目链接:http://codefor ...

  2. [USACO11NOV]牛的障碍Cow Steeplechase(匈牙利算法)

    洛谷传送门 题目描述: 给出N平行于坐标轴的线段,要你选出尽量多的线段使得这些线段两两没有交点(顶点也算),横的与横的,竖的与竖的线段之间保证没有交点,输出最多能选出多少条线段. 因为横的与横的,竖的 ...

  3. react.js 给标识ref,获取内容

    import React,{Component} from 'react' import ReactDOM from 'react-dom' class App extends Component{ ...

  4. THUWC2018 暴力+爆炸记

    Day 0 没有Day0. Day 1 签到然后去宿舍,环境还行,比某偏远山区要强多了,不过这热水有点难拿??看RP有遇到煮好水的饮水机就拿,没有就苟矿泉水. 中午,那个餐还是挺好吃的,不过餐费40就 ...

  5. BZOJ1704: [Usaco2007 Mar]Face The Right Way 自动转身机

    n<=5000个数0或1,每次可以连续对固定长度区间取反,目标把所有1变0,求一个取反区间的固定长度K使取反次数最少. 答案关于K不单调,因此枚举K,对每个K扫一遍区间,遇到1就把连续K个数反转 ...

  6. 指针与数组的对比(——选自:C++内存管理技术内幕)

    数组: 数组要么是在静态存储区上创建(如全局数组),要么是在栈上创建的.数组名代表着 段连续的内存,其地址和容量在生命周期内是不会改变的,而只能改变其数组内容. 指针: 指针是一种指针类型的变量,变量 ...

  7. python学习之-- redis模块管道/订阅发布

    redis 模块操作剩余其他常用操作 delete(*names):删除任意的数据类型exists(name):检测redis的name是否存在keys(pattern='*'):根据模型获取redi ...

  8. python学习之-- redis模块基本介绍

    数据缓存系统: 1:mongodb:是直接持久化,直接存储于硬盘的缓存系统 2:redis: 半持久化,存储于内存和硬盘 3:memcache:数据只能存储在内存里的缓存系统关于memcache 学习 ...

  9. topcoder 650 srm

    500 遇到这种构造题 就给跪了 比赛的时候想很多方法 DP,贪心,模拟 发现越写越烦琐.看到别人出这么快,肯定又是奇葩思路. 后来居然想到 2^50的暴力 +剪枝 不过暴力肯定卡你 IDEA: 只要 ...

  10. jfree-生成xy图

    需要导入的包: import org.jfree.chart.*; import org.jfree.chart.plot.PlotOrientation; import org.jfree.data ...