HYSBZ 2038 莫队算法

来源:互联网 发布:hbase快速清空表数据 编辑:程序博客网 时间:2024/05/16 02:48

题意

中文题,不解释

题解

莫队入门题。其实莫队就是暴力,只不过利用了上一次计算的结果,同时对区间进行合理分块,可以使得复杂度可以降低到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 LLusing 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);    }}
原创粉丝点击