算法简介
莫队算法,是一种用于解决序列上的问题的离线算法,可以回答对于区间的询问,非常bug。
算法流程
先读入所有的询问,对询问的左端点分块。
在对询问排序,以左端点的块编号为第一关键字,以右端点为第二关键字。
然后遍历询问,同时维护L,R以及答案:对于当前区间,[l,r],不断移动左端点与右端点,直至l==L&&r==R。
算法复杂度
算法复杂度为
O(nn−√)
,可以用意识流跑一遍:
对于同一个块,R最多移动n次,然而,一共只有
n−√
个块,所以复杂度就是
O(nn−√)
。
对于左端点,先讨论同一个块中的情况,每次移动至多为
n−√
,于是总复杂度为
O(nn−√)
,对于不同块中的情况,只有
n−√
个,即使每次
O(n)
也没关系。
综上,莫队算法的复杂度就是
O(nn−√)
。
入门题——小Z的袜子
题目链接
令
Ti
表示数i在
[L,R]
中出现的次数。
P=∑C2iC2R−L+1=∑Ti∗(Ti−1)/2(R−L+1)∗(R−L)/2=∑T2i−∑Ti(R−L+1)∗(R−L)
显然
∑Ti
=R-L+1,所以只要求
∑T2i
就可以了。
这时我们惊奇的发现,似乎把刚学的莫队算法套上去就可以了!
用
cnti
表示元素i在当前区间中出现的次数。
每次添加一个元素,就往答案中加
(cnti+1)2−cnt2i
,再
cnti++
这就是刚加入到元素的贡献。
每次删除一个元素,就减掉
cnt2i−(cnti−1)2
,再
cnti−−
。
每次操作都是
O(1)
的,所以总复杂度是
O(nn−√)
。
/**************************************************************
Problem: 2038
User: unicornt
Language: C++
Result: Accepted
Time:1540 ms
Memory:2788 kb
****************************************************************/
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=50005;
typedef long long ll;
struct Query{
int L,R,id;
}q[M];
int s,col[M];
ll ans[M][2],cnt[M];
bool cmp(Query a,Query b){
if(a.L/s==b.L/s) return a.R<b.R;
return a.L/s<b.L/s;
}
int gcd(ll a,ll b){
return a?gcd(b%a,a):b;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
s=(int)sqrt(n);
for(int i=1;i<=n;i++)
scanf("%d",&col[i]);
for(int i=0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
q[i]=(Query){a,b,i};
}
sort(q,q+m,cmp);
int L=1,R=0;
ll res=0;
for(int i=0;i<m;i++){
while(R<q[i].R){
R++;
res+=(cnt[col[R]]+1)*(cnt[col[R]]+1)-cnt[col[R]]*cnt[col[R]];
cnt[col[R]]++;
}
while(L<q[i].L){
res-=cnt[col[L]]*cnt[col[L]]-(cnt[col[L]]-1)*(cnt[col[L]]-1);
cnt[col[L]]--;
L++;
}
while(R>q[i].R){
res-=cnt[col[R]]*cnt[col[R]]-(cnt[col[R]]-1)*(cnt[col[R]]-1);
cnt[col[R]]--;
R--;
}
while(L>q[i].L){
L--;
res+=(cnt[col[L]]+1)*(cnt[col[L]]+1)-cnt[col[L]]*cnt[col[L]];
cnt[col[L]]++;
}
ans[q[i].id][0]=res-R+L-1;
ans[q[i].id][1]=1LL*(R-L+1)*(R-L);
}
for(int i=0;i<m;i++){
int G=gcd(ans[i][0],ans[i][1]);
ans[i][0]/=G;
ans[i][1]/=G;
if(!ans[i][0]) ans[i][1]=1;
}
for(int i=0;i<m;i++)
printf("%lld/%lld\n",ans[i][0],ans[i][1]);
return 0;
}
一些题
codeforces 375D Tree and Queries 题解
codeforces 86D power array题解
hdu 4638 Group 题解