【bzoj 2038】 [2009国家集训队]小Z的袜子(算法效率--莫队分块算法 模版题)

题意:小Z有N只袜子,有不同的颜色。他有M个提问,问从编号为[L,R]的袜子中随机选一双同色的袜子的概率,用最简分数表示。

解法:经典的莫队算法——无修改、不强制在线(可离线)、状态转移可以一步完成。

步骤如下:
     1.对询问按第一关键字的平方根 sqrt(x) 从小到大排序进行分组,再是各组中按第二关键字 y 从小到大排序。O(m log m)。
     2.一步步转移,第一关键字最多转移 O(sqrt(n)),第二关键字是 O(n) ,相结合就是 O(n*sqrt(n))。
总时间复杂度就是 O(n*sqrt(n))。

P.S.我第一个代码WA怎么改都对不了,应该是不能直接对颜色的计数数组通过 +1 和 -1 对答案的贡献不同而直接转移状态。而要减去原来该数对答案的贡献,再加上新的贡献。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<iostream>
 6 #include<cmath>
 7 using namespace std;
 8 typedef long long LL;
 9  
10 const int N=50010,M=50010,D=50010;
11 int n,m,sqn;
12 int c[N],h[N];
13 LL ans[M][2];
14 struct query{int l,r,id;}q[M];
15  
16 bool cmp(query x,query y)
17 {
18     int xx=x.l/sqn,yy=y.l/sqn;
19     if (xx!=yy) return xx<yy;
20     return x.r<y.r;
21 }
22 int read()
23 {
24     char ch=getchar();
25     int x=0;
26     while (ch<'0'||ch>'9') ch=getchar();
27     while (ch>='0'&&ch<='9') x=x*10+ch-'0', ch=getchar();
28     return x;
29 }
30 LL gcd(int x,int y) {return y?gcd(y,x%y):x;}
31 int main()
32 {
33     n=read(),m=read();
34     for (int i=1;i<=n;i++) c[i]=read();
35     for (int i=1;i<=m;i++)
36     {
37       q[i].l=read(),q[i].r=read();
38       q[i].id=i;
39     }
40     sqn=sqrt(n);
41     sort(q+1,q+1+m,cmp);
42      
43     int l=1,r=1;
44     LL sum=0;
45     memset(h,0,sizeof(h));
46     h[c[1]]++;
47     for (int i=1;i<=m;i++)
48     {
49       while (l<q[i].l) sum=sum-2*h[c[l]]+2,h[c[l]]--,l++;
50       while (r>q[i].r) sum=sum-2*h[c[r]]+2,h[c[r]]--,r--;
51       while (l>q[i].l) l--,sum+=2*h[c[l]],h[c[l]]++;
52       while (r<q[i].r) r++,sum+=2*h[c[r]],h[c[r]]++;
53       LL w=(q[i].r-q[i].l)*(q[i].r-q[i].l+1);
54       LL gd=gcd(sum,w);
55       ans[q[i].id][0]=sum/gd,ans[q[i].id][1]=w/gd;
56     }
57     for (int i=1;i<=m;i++)
58       printf("%I64d/%I64d\n",ans[i][0],ans[i][1]);
59     return 0;
60 }
WA
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<iostream>
  6 using namespace std;
  7 const int Max=50010;
  8 int n,m,t=0;
  9 int s[Max],c[Max],ans1[Max],ans2[Max];
 10 struct hp{int l,r,t,k;}
 11 a[Max];
 12 int gcd(int x,int y)
 13 {
 14     if (x<y) swap(x,y);
 15     if (x%y==0) return y;
 16     return gcd(y,x%y);
 17 }
 18 int cmp(const void *x,const void *y)
 19 {
 20     hp xx=*(hp *)x;
 21     hp yy=*(hp *)y;
 22     if (xx.t==yy.t) return xx.r-yy.r;
 23     return xx.t-yy.t;
 24 }
 25 int make(int x)
 26 {   //if (x<2) return 0;
 27     if (x%2==0) return (x/2)*(x-1);
 28     return x*((x-1)/2);
 29 }
 30 void block(int id,int l,int r,int ll,int rr)
 31 {
 32     /*if (ll<l)
 33       for (int i=ll;i<l;i++)
 34       {//因为ll为0,所以每次都会make(-1),出现负数便错误!//若特殊算第一次,或算1~n为初始值,才行
 35   //幸亏我想着算组合make时,若x<2宣布了2个怎么办,没有进一步看x=0或1时不会算错,就加了判断语句,便发现对了一些
 36         t-=make(s[c[i]]);
 37         s[c[i]]--;
 38         t+=make(s[c[i]]);
 39       }*/
 40     if (ll<l)
 41       for (int i=ll;i<l;i++)
 42       {
 43         t-=make(s[c[i]]);
 44         s[c[i]]--;
 45         t+=make(s[c[i]]);
 46       }
 47     if (ll>l)
 48       for (int i=l;i<ll;i++)
 49       {
 50         t-=make(s[c[i]]);
 51         s[c[i]]++;
 52         t+=make(s[c[i]]);
 53       }
 54     if (rr<r)
 55       for (int i=rr+1;i<=r;i++) 
 56       {
 57         t-=make(s[c[i]]);
 58         s[c[i]]++;
 59         t+=make(s[c[i]]);
 60       }
 61     if (rr>r)
 62       for (int i=r+1;i<=rr;i++)
 63       {
 64         t-=make(s[c[i]]);
 65         s[c[i]]--;
 66         t+=make(s[c[i]]);
 67       }
 68     int tt,x;
 69     if (!t) {ans1[a[id].k]=0; ans2[a[id].k]=1; return;}
 70     tt=make(r-l+1);//t/tt
 71     x=gcd(tt,t);
 72     ans1[a[id].k]=t/x;
 73     ans2[a[id].k]=tt/x;
 74 }
 75 int main()
 76 {
 77     //freopen("a.in","r",stdin);
 78     //freopen("b.out","w",stdout);
 79     scanf("%d%d",&n,&m);
 80     
 81     for (int i=1;i<=n;i++)
 82       scanf("%d",&c[i]);
 83     double x=sqrt(n);
 84     for (int i=1;i<=m;i++)
 85     {
 86       scanf("%d%d",&a[i].l,&a[i].r);
 87       a[i].t=(int)(a[i].l/x);
 88       a[i].k=i;
 89     }
 90     qsort(a+1,m,sizeof(hp),cmp);
 91     
 92     memset(s,0,sizeof(s));
 93     //a[0].l=0; a[0].r=0;
 94     a[0].l=1;a[0].r=n;
 95     for (int i=1;i<=n;i++) s[c[i]]++;
 96     for (int i=1;i<=n;i++)
 97       t+=make(s[i]);
 98     for (int i=1;i<=m;i++)
 99       block(i,a[i].l,a[i].r,a[i-1].l,a[i-1].r);
100     for (int i=1;i<=m;i++)
101       printf("%d/%d\n",ans1[i],ans2[i]);
102   //system("pause");
103     return 0;
104 }
AC

 

posted @ 2016-11-15 11:33  konjac蒟蒻  阅读(176)  评论(0编辑  收藏  举报