题目链接: 小Z的袜子
思路
莫队算法用于解决离线处理问题,即先把所有询问记录一遍,对询问的进行排序操作后,最终一起输出答案。对于区间询问,其实我们就是设置了两个指针L,R,我们其实可以在O(1)的时间内完成从【L,R】的询问到【L+1,R】或者是【L,R+1】的询问,因此排序的原因就是使得指针跳来跳去的次数能够减少一些。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
ll l,r,A,B,id;
}q[50001];
ll col[50001],sum[50001],ans,a[50001],n,m;
ll cmp(node a,node b)
{
return col[a.l]==col[b.l]?(a.r<b.r):(a.l<b.l);
}
ll cmp1(node a,node b)
{
return a.id < b.id;
}
ll update(ll x,ll add)
{
ans -= sum[a[x]]*sum[a[x]];
sum[a[x]] += add;
ans += sum[a[x]]*sum[a[x]];
}
ll gcd(ll x,ll y)
{
return y==0?x:gcd(y,x%y);
}
int main()
{
ll i;
cin >> n >> m;
for(i = 1 ;i <= n ; i++)
{
cin >> a[i];
col[i] = i/int(sqrt(n))+1;
}
for(i = 1; i <= m ; i++)
{
cin >> q[i].l >> q[i].r;
q[i].id = i;
}
sort(q+1,q+m+1,cmp);
int l = 1 ,r = 0;
for(i = 1;i <= m ; i++)
{
while(l < q[i].l) {update(l,-1),l++;}
while(l > q[i].l) {update(l-1,1),l--;}
while(r < q[i].r) {update(r+1,1),r++;}
while(r > q[i].r) {update(r,-1),r--;}
if(l == r) {q[i].A =0 ;q[i].B =1;continue;}
q[i].A = ans - (q[i].r-q[i].l+1);
q[i].B = (q[i].r - q[i].l + 1)*(q[i].r - q[i].l);
ll g = gcd(q[i].A,q[i].B);
q[i].A = q[i].A /g;
q[i].B = q[i].B /g;
}
sort(q+1,q+m+1,cmp1);
for(i = 1; i <= m ;i++)
{
printf("%lld/%lld\n",q[i].A,q[i].B);
}
return 0;
}
题目链接 HDU-5213
思路
首先我们要知道莫队算法在求的时候需要一段连续的区间,然后再这段连续的区间中求题目要求的,比如说这道题就是求区间内两个数的和为K的对数,但是这道题是给你两段区间让你求对数,所以这个时候我们应该先用容斥原理来处理一下。
然后我们就可以分别求每个区间上的对数在进行求和了。
#include <bits/stdc++.h>
using namespace std;
const int N = 30001 * 4;
struct node{
int l,r,id,f;
}q[N];
int num[N],sum,tot,a[N],ans[N],Be[N],k;
void add(int l,int r,int id,int f)
{
q[++tot] = node{l,r,id,f};
}
int cmp(node A,node B)
{
return Be[A.l] == Be[B.l]?A.r<B.r:A.l<B.l;
}
void update(int x,int d)
{
if(d > 0)
{
if(k >= x)
sum += num[k-x];
num[x]++;
}
else
{
num[x]--;
if(k >= x)
sum -= num[k-x];
}
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(0);
int n,m,i,block,l,r,u,v;
while(cin >> n >> k)
{
tot = sum = 0;
block = (int)sqrt(n);
memset(num,0,sizeof(num));
memset(ans,0,sizeof(ans));
for(i = 1 ;i <= n ; i++)
{
cin >> a[i];
Be[i] = i/block + 1;
}
cin >> m;
for(i = 1;i <= m ; i++)
{
cin >> l >> r >> u >> v;
add(l,v,i,1);
add(l,u-1,i,-1);
add(r+1,v,i,-1);
add(r+1,u-1,i,1);
}
sort(q+1,q+tot+1,cmp);
int l = 1,r = 0;
for(i = 1;i <= tot ; i++)
{
while(l < q[i].l) {update(a[l++],-1);}
while(l > q[i].l) {update(a[--l],1);}
while(r < q[i].r) {update(a[++r],1);}
while(r > q[i].r) {update(a[r--],-1);}
ans[q[i].id] += q[i].f*sum;
}
for(i = 1 ;i <= m ;i++)
{
cout << ans[i] << endl;
}
}
}