bzoj2038 小Z的袜子(hose) 莫队算法(不修改只查询 基础版)

来源:互联网 发布:java多态的实现原理 编辑:程序博客网 时间:2024/06/10 22:58

题目链接:bzoj2038

题目思路:莫队算法 可参考博客:点击打开链接

这道题是比较模板的莫队分块了,对于一个区间询问[L,R],我们要求的ans是
ans=(Σsum(color[i])1)sum(color[i])/2)/((RL+1)(RL))
简化可得
ans=(Σ(sum(color[i])2)(RL+1))/((RL+1)(RL))
其中sum(color[i])指第i种颜色在[L,R]中出现的次数
那么我们现在求出各个询问区间中sum(color[i])2就行了,具体实现方法参照代码
注意:
1.当一种颜色数量ci增加1时,我们可以看出ans=ansci2+(ci+1)2,简化可得ans=ans+(ci2+1),同样减少1时,ans=ansci2+(ci1)2,简化得ans=ans-ci2+1,这样做的好处是减少乘法且可用位运算,优化常数(然而并没有什么卵用)
2.极限数据50000*50000如 果不用longlong会教你做人←_←

#include <cstdio>#include <cmath>#include <algorithm>using namespace std;const int maxn = 50000 + 500;typedef long long LL;LL gcd(LL a,LL b){    return (b==0)?a:gcd(b,a%b);}int pos[maxn];int col[maxn];int f[maxn];int n,m;struct Query{    int l,r,id;    LL a,b;    friend bool operator < (const Query &R,const Query &T)    {        return pos[R.l]<pos[T.l] || (pos[R.l]==pos[T.l] && R.r<T.r);        //先按模块排序,模块从小到大        //在同一个模块时   再按r从小到大排序    }    void modify()//分子分母的化简    {        LL k=gcd(a,b);        a/=k,b/=k;    }}Q[maxn];bool cmp_id(const Query &a,const Query &b){    return a.id<b.id;}void init(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;++i)        scanf("%d",&col[i]);    int limit=(int)sqrt((double)n+0.5);    for(int i=1;i<=n;++i)        pos[i]=(i-1)/limit+1;//左端点分块    for(int i=1;i<=m;++i)    {        scanf("%d%d",&Q[i].l,&Q[i].r);        Q[i].id=i;    }    sort(Q+1,Q+m+1);}void modify(int p,LL &ans,int add){    ans=ans+2*add*f[col[p]]+1;    f[col[p]]+=add;}void solve(){    LL ans=0;    int l=1,r=0;    for(int i=1;i<=m;++i)    {        if(r<Q[i].r)        {            for(r=r+1;r<Q[i].r;++r)                modify(r,ans,1);            modify(r,ans,1);        }        if(Q[i].l<l)        {            for(l=l-1;Q[i].l<l;--l)                modify(l,ans,1);            modify(l,ans,1);        }        if(Q[i].r<r)            for(;Q[i].r<r;--r)                modify(r,ans,-1);        if(l<Q[i].l)            for(;l<Q[i].l;++l)                modify(l,ans,-1);        if(Q[i].l==Q[i].r)        {            Q[i].a=0,Q[i].b=1;            continue;        }        Q[i].a=ans-(Q[i].r-Q[i].l+1),Q[i].b=(LL)(Q[i].r-Q[i].l+1)*(Q[i].r-Q[i].l);        Q[i].modify();    }    sort(Q+1,Q+m+1,cmp_id);    for(int i=1;i<=m;++i)        printf("%lld/%lld\n",Q[i].a,Q[i].b);}int main(){    init();//离线算法  先将m组询问输入  然后之后再输出    solve();    return 0;}


阅读全文
0 0