bzoj 2038

因为考试题太难了改不出,于是就弃疗搞莫队算法去了


参考:《莫涛2010年集训队论文》


hzwer的写法极其简略,长跪不起


具体实现:
1.分块 S=sqrt(n)+ 双关键字排序
2.如下

 

[来自莫涛论文]

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
const int MAXN = 50005, MAXM = 50005;

int n , m , S;
int color[MAXN] = {0}, cnt[MAXN] = {0};
int  l , r ;long long now ;

struct ques{int l,r,si,Num;long long a,b;}q[MAXM] = {0};

bool cmp(const ques &a, const ques &b)
{return (a.si < b.si)||(a.si == b.si && a.r < b.r);}
bool ncmp(const ques &a, const ques &b)
{return a.Num<b.Num;}

long long gcd(long long a,long long b){if(!b)return a;else return gcd(b,a%b);}

long long pow2(int x){return (long long)x*x;}

void add(int t,int w)
{
    now -= pow2(cnt[color[t]]);
    cnt[color[t]]+=w;
    now += pow2(cnt[color[t]]);
}

int main()
{
#ifndef ONLINE_JUDGE    
    freopen("bzoj2038.in","r",stdin);
    freopen("bzoj2038.out","w",stdout);
#endif

     scanf("%d%d",&n,&m);

     S = sqrt((double)n);

     for(int i = 1; i <= n; i++)
        scanf("%d",&color[i]);

     for(int i = 1; i <= m ; i++)
     {
       scanf("%d%d",&q[i].l,&q[i].r);   
       q[i].Num = i;
       q[i].si = (q[i].l-1)/S + 1;
     }

     std::sort(q+1,q+m+1,cmp);

     cnt[color[1]] = 1, l = r = 1 , now = 1;
     for(int i = 1; i <= m; i++)
     {
        if(l<=q[i].l) while(l < q[i].l){add(l,-1);l++;}
        else          while(l > q[i].l){--l;add(l,1);}

        if(r<=q[i].r) while(r < q[i].r){++r;add(r,1);}
        else          while(r > q[i].r){add(r,-1);r--;}

        if(q[i].l == q[i].r){q[i].a = 0 ,q[i].b = 1;}
        else
        {
         q[i].a = now - (r-l+1);
         q[i].b = ((long long)r-l+1)*(r-l);

         long long tmp = gcd(q[i].a,q[i].b);
         q[i].a/= tmp , q[i].b/=tmp;
        }
     }

     std::sort(q+1,q+m+1,ncmp);

     for(int i = 1 ; i <= m ; i++)
        printf("%lld/%lld\n",q[i].a,q[i].b);

#ifndef ONLINE_JDUGE
     fclose(stdin);
     fclose(stdout);
#endif      
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值