zoukankan      html  css  js  c++  java
  • bzoj2038[2009国家集训队]小Z的袜子(hose)

    bzoj2038[2009国家集训队]小Z的袜子(hose)

    题意:

    把N只袜子从1到N编号,每次求从编号为L到R的袜子中抽两只,有多大的概率抽到颜色相同的袜子。

    题解:

    不知道要用什么数据结构,但是可以用一个全局的数组保存每个颜色当前数量,使由区间[l,r]推出[l,r±1]的答案和[l±1,r]的复杂度为O(1),对这种问题,可以用复杂度为O(nsqrt(n))的莫队算法解决。

    莫队算法是一种离线算法,将询问按某种顺序排序,使得均摊复杂度为O(nsqrt(n)),那怎么排序呢?如果按左端点排序,那么r将有可能多次大幅度摆动,使复杂度退化成O(n^2),正解是对端点分块,让后按左端点所在块为第一关键字排序,右端点为第二关键字排序。这样子当两个询问l在同一块时,l只有可能移sqrt(n)次。l在同一块的多次询问q只能右移n次,l在不同块时r可能左移n次,但因为只有sqrt(n)块,所以需移n次的操作都只有sqrt(n)次,因此均摊复杂度是O(sqrt(n))。所有的均摊复杂度都是玄学……

    因为中间结果没有强制转化成long long,wa了好几发,本弱太弱了!

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <cmath>
     5 #define ll long long
     6 #define inc(i,j,k) for(int i=j;i<=k;i++)
     7 using namespace std;
     8 
     9 struct nd1{
    10     int l,pl,r,id; ll ans;
    11 };
    12 bool cmp1(nd1 a,nd1 b){
    13     if(a.pl!=b.pl)return a.pl<b.pl; if(a.r!=b.r)return a.r<b.r;
    14     return a.l<b.l;
    15 }
    16 bool cmp2(nd1 a,nd1 b){
    17     return a.id<b.id;
    18 }
    19 nd1 a1[100000];int col[100000],pos[100000],n,m,l,r;ll ans,s[100000];
    20 inline void update(int x,int y){
    21     ans-=(s[col[x]]*(s[col[x]]-1));s[col[x]]+=(ll)y;ans+=(s[col[x]]*(s[col[x]]-1));
    22 }
    23 ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
    24 int main(){
    25     scanf("%d%d",&n,&m); inc(i,1,n)scanf("%d",&col[i]); int sz=(int)sqrt(n);
    26     inc(i,1,n)pos[i]=(i-1)/sz+1;
    27     inc(i,1,m){
    28         int a,b;scanf("%d%d",&a,&b);a1[i]=(nd1){a,pos[a],b,i,0};
    29     }
    30     sort(a1+1,a1+1+m,cmp1); l=1; r=0; ans=0; memset(s,0,sizeof(s));
    31     inc(i,1,m){
    32         while(r<a1[i].r)update(r+1,1),r++;
    33         while(l>a1[i].l)update(l-1,1),l--;
    34         while(r>a1[i].r)update(r,-1),r--;
    35         while(l<a1[i].l)update(l,-1),l++;
    36         a1[i].ans=ans;
    37     }
    38     sort(a1+1,a1+1+m,cmp2); 
    39     inc(i,1,m){
    40         if(a1[i].ans==0)printf("0/1
    ");else{
    41             ll a2=gcd(a1[i].ans,(ll)(a1[i].r-a1[i].l+1)*(a1[i].r-a1[i].l));
    42             printf("%lld/%lld
    ",a1[i].ans/a2,(ll)(a1[i].r-a1[i].l+1)*(a1[i].r-a1[i].l)/a2);
    43         }
    44     }
    45     return 0;
    46 }

    20160405

  • 相关阅读:
    5.常见类和API
    4.异常
    3.面向对象
    2.控制语句和数组
    1.初始java 数据类型 运算符
    C#设计模式——桥接模式
    C#设计模式——适配器模式
    C#设计模式——原型模式
    C#设计模式——建造者模式
    C#设计模式——抽象工厂模式
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5693162.html
Copyright © 2011-2022 走看看