题意
中文题,不解释
题解
莫队入门题。其实莫队就是暴力,只不过利用了上一次计算的结果,同时对区间进行合理分块,可以使得复杂度可以降低到O(N^(3/2))。题目要求求区间内任意选两个数,相同的概率。如果时间宽松一点,对于稍微有点数学基础的选手都可以在5分钟内写出相应代码,组合数公式随便搞一下就可以。
对于这道题就不行了,不但不能暴力,并且用什么数据结构都会感觉不舒服(会各种树套树的大牛可以无视此句。)不过我们可以用莫队算法优化一下暴力流程,我们可以将整个数轴分为M块,每块的大小为sqrt(MX))(MX为数轴最大值)然后我们可以进行排序,在同一块的元素放在一起。
至于分块的原因其实很简单,如果直接排序的话,很容易被卡。比如说(100,1),(50,1000),(1,1)这样一个样例。由于莫队是利用上一次结果进行转移,那么这个样例就需要先从1转移到1000,然后再从1000转移到1。明显可以看出来这样是不好的。所以我们可以允许X在一定范围内非单增,比如我们可以把一块设置为100,那么在这一块内便根据Y排序,那么便会排列成(100,1),(1,1),(50,1000),这样的话转移变少了1000次,优化很明显。
解决了分快的问题,莫队算法的核心基本就解决了。另外的话,莫队算法还有一个核心就是,对于每一个查询,不直接计算,而是通过上一个状态转移的这一个状态来计算值,这样分块的作用才能达到。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#include<stack>
#include<string>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define MEM(a,b) memset(a,b,sizeof(a))
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN 50010
#define MOD 1000000007
#define EPS 1e-3
#define int LL
using namespace std;
struct Node{
int l,r,id,val,all;
};
int c[MAXN],pos[MAXN],cnt[MAXN],val;
Node nodes[MAXN];
int n,m;
bool cmp(Node a,Node b){
return pos[a.l]==pos[b.l]?a.r<b.r:a.l<b.l;
}
bool cmp1(Node a,Node b){
return a.id<b.id;
}
void update(int p,int add){
val-=cnt[p]*(cnt[p]-1)/2;
cnt[p]+=add;
val+=cnt[p]*(cnt[p]-1)/2;;
}
void solve(){
MEM(cnt,0);
int l=1,r=1;
val=0;
update(c[1],1);
UP(i,0,m){
nodes[i].all=(nodes[i].r-nodes[i].l+1)*(nodes[i].r-nodes[i].l)/2;
for(;l<nodes[i].l;l++) update(c[l],-1);
for(;l>nodes[i].l;l--) update(c[l-1],1);
for(;r>nodes[i].r;r--) update(c[r],-1);
for(;r<nodes[i].r;r++) update(c[r+1],1);
nodes[i].val=val;
}
}
main() {
scanf("%lld%lld",&n,&m);
UP(i,1,n+1) scanf("%lld",&c[i]);
int mx=0;
UP(i,0,m){
scanf("%lld%lld",&nodes[i].l,&nodes[i].r);
nodes[i].id=i;
mx=max(mx,nodes[i].l);
}
int q=sqrt(mx);
UP(i,1,mx+1) pos[i]=i/q;
sort(nodes,nodes+m,cmp);
solve();
sort(nodes,nodes+m,cmp1);
UP(i,0,m){
int g=__gcd(nodes[i].val,nodes[i].all);
if(g==0) printf("0/1\n");
else printf("%lld/%lld\n",nodes[i].val/g,nodes[i].all/g);
}
}