简单莫对算法 --- 离线处理所有询问

来源:互联网 发布:测绘数据泄密案例 编辑:程序博客网 时间:2024/05/18 12:36

思想: 先把所有的询问全部记下来. 然后通过一定的技巧使得暴力的复杂度不高, 从而达到目的, 一次性全部输出答案.

以这两道模板题来说明一下它如何暴力的更漂亮.
复杂度为 O n ^ 3/2 ; (2e5是可以跑的)
小Z的袜子
AC Code

#include <bits/stdc++.h>#define ll long longusing namespace std;const int maxn = 5e4+5;int a[maxn];ll fz[maxn],fm[maxn];int times[maxn];int block;struct node{    int l,r,id;}s[maxn];bool cmp(node x,node y){    if(x.l/block==y.l/block)        return x.r<y.r;    return x.l<y.l;}int main(){    int n,q;    scanf("%d%d",&n,&q);    for(int i=1; i<=n; i++)        scanf("%d",&a[i]);    for(int i=1; i<=q; i++){        scanf("%d%d",&s[i].l,&s[i].r);        s[i].id=i;    }    block=(int)sqrt(n+0.5);    sort(s+1,s+q+1,cmp);    int l = 1 , r = 1;    //范围是[l,r);    ll sum = 0;    for(int i=1;i<=q;i++){        while(l < s[i].l){            times[a[l]]--;            sum -= times[a[l]] ;   //唯一需要点推理的就是多加一次少加一次对sum总体的影响. 即times怎么变.            l++;        }        while(l > s[i].l){            l--;            sum += times[a[l]];            times[a[l]]++;        }        while(r < s[i].r+1){   //所以注意下范围然后就可以写出来了.            sum += times[a[r]];            times[a[r]]++;            r++;        }        while(r > s[i].r+1){            r--;            times[a[r]]--;            sum -= times[a[r]];        }        ll len = s[i].r+1-s[i].l;        ll t = __gcd(len*(len-1)/2,sum);        fz[s[i].id] = sum/t;        fm[s[i].id] = len*(len-1)/2/t ;    }    for(int i=1;i<=q;i++){        printf("%lld/%lld\n",fz[i],fm[i]);    }}

Powerful Array

#include <bits/stdc++.h>#define ll long longusing namespace std;const int maxn = 2e5+5;int a[maxn];ll res[maxn];int times[maxn * 5];int block;struct node{    int l,r,id;}s[maxn];bool cmp(node x,node y){    if(x.l/block==y.l/block)        return x.r<y.r;    return x.l<y.l;}int main(){    int n,q;    scanf("%d%d",&n,&q);    for(int i=1; i<=n; i++)        scanf("%d",&a[i]);    for(int i=1; i<=q; i++){        scanf("%d%d",&s[i].l,&s[i].r);        s[i].id=i;    }    block=(int)sqrt(n+0.5);    sort(s+1,s+1+q,cmp);    int l = 1 , r = 1;    //范围是[l,r);    ll sum = 0;    for(int i=1;i<=q;i++){        while(l < s[i].l){            times[a[l]]--;            sum -= a[l] * (times[a[l]] * 2 + 1);            l++;        }        while(l > s[i].l){            l--;            sum += a[l] * (times[a[l]] * 2 + 1);            times[a[l]]++;        }        while(r < s[i].r+1){   //所以注意下范围然后就可以写出来了.            sum += a[r] * (times[a[r]] * 2 + 1);            times[a[r]]++;            r++;        }        while(r > s[i].r+1){            r--;            times[a[r]]--;            sum -= a[r] * (times[a[r]] * 2 + 1);        }        res[s[i].id] = sum;    }    for(int i=1;i<=q;i++)        printf("%lld\n",res[i]);}