首页 > 代码库 > BJOI2014 想法

BJOI2014 想法

3765. 【BJOI2014】想法 (Standard IO)

Time Limits: 4000 ms  Memory Limits: 262144 KB       Special Judge

Description

小强和阿米巴是好朋友。

小强要出一套题目。他的题目以涉及面广(偏)、考察深入(怪)、思维强度大(难)著称。他为了出题,一共攒了M个本质不同的想法,每个想法形成了一个题目。不过,他觉得拿这些题目去考察选手会把比赛搞的太过变态,所以,想请阿米巴来帮忙调整一下他的题目。

阿米巴指出,为了让一场考试的题目的考察点尽量全面,有一个通用的做法叫做“组合”。如果把两个题目A和B组合在一起,那么组合而成的题目涉及到的想法的集合就是A涉及到的想法的集合和B涉及到的想法的集合的并。

并且,题目是可以反复组合的。

例如,小强现在有三个想法1,2,3,分别对应了题目P1,P2,P3。

现在,小强把P1和P2组合得到P4。P4涉及的想法的集合是{1,2}。

之后,小强把P2和P3组合得到P5。P5涉及的想法的集合是{2,3}。

最后,小强把P4和P5组合得到P6。P6涉及的想法的集合是{1,2,3}。

现在,小强告诉你每个题目都是如何组合而来的。你要回答的就是,每个题目涉及的想法的集合有多大。

不过,这个问题是很难的。于是,你只需要能够以比较高的概率回答的比较准确即可。
 

Input

第一行两个整数N,M,依次表示小强的题目数量和想法的数量

接下来N-M行,每行两个整数,依次表示小强组合出来的题目都是由哪两个题组合而成的。M个想法对应的题目依次编号为1~M。之后,小强组合出来的第一个题编号为M+1,组合出来的第二个题编号为M+2,依次类推。

Output

输出N-M行,每行一个整数表示小强组合出来的每个题都涉及了几个想法。
 

Sample Input

6 3

1 2

2 3

4 5

Sample Output

2

2

3
 

Data Constraint

对于30%的数据,M≤1000,N≤10000

对于60%的数据,M≤10000,N≤100000

对于100%的数据,M≤100000,N≤1000000
 

Hint

【评分方法】

对于每个输出文件,如果其中你有95%以上的行的答案和正确答案的误差不超过25%,那么你就可以得到分数。所谓误差不超过25%,即,如果正确答案是X,那么你的答案在[0.8X,1.25X]这个闭区间内。
 

 

 

60分直接压位即可

接下来说说满分的神级做法:

随机大法!

对于每个想法Random一个随机器代表它,合并的时候保留前T小的数。最后的答案即是T*RAND_MAX/(第T小的数)

为什么这样可以呢?

设包含的总想法数为L,在L中取到T的期望为T/L,而随机数是均匀分布的,所以T/L会等于RAND_T/RAND_MAX,所以L=T*RAND_MAX/RAND_T

 

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<cstring>#include<ctime>using namespace std;double r;int son[1000111][2];int a[1001111][31];int tt,n,m,T,tl,mx,i,x,z,seed,t,lim;double ans[1000111];void cger(int *a,int *b,int *c){    int j,k,i,al,bl;    al=1;    bl=1;    c[0]=0;    while(al<=a[0]&&bl<=b[0]){        if(a[al]<b[bl]){            if(a[al]!=c[c[0]]){                c[0]++;                c[c[0]]=a[al];            }            al++;        }        else{            if(b[bl]!=c[c[0]]){                c[0]++;                c[c[0]]=b[bl];            }            bl++;        }        if(c[0]==lim)break;    }    if(c[0]!=lim){        while(al<=a[0]){            if(a[al]!=c[c[0]]){                c[0]++;                c[c[0]]=a[al];            }            al++;            if(c[0]==lim)break;        }        while(bl<=b[0]){            if(b[bl]!=c[c[0]]){                c[0]++;                c[c[0]]=b[bl];            }            bl++;            if(c[0]==lim)break;        }    }}int main(){    srand((unsigned)time(0));    seed=1;    scanf("%d%d",&n,&m);    lim=20;    for(i=m+1;i<=n;i++){        scanf("%d%d",&x,&z);        son[i][0]=x;        son[i][1]=z;    }    T=10000000/n;    for(tl=1;tl<=T;tl++){        mx=0;        for(i=1;i<=m;i++){            a[i][1]=rand()+1;            a[i][0]=1;        }        for(i=m+1;i<=n;i++)a[i][0]=0;        for(i=m+1;i<=n;i++){            cger(a[son[i][0]],a[son[i][1]],a[i]);            if(a[i][0]<lim)ans[i]+=a[i][0];            else ans[i]=ans[i]+(double)lim*(double)RAND_MAX/(double)a[i][a[i][0]];        }    }    for(i=m+1;i<=n;i++){        t=(int)(ans[i]/(double)T+0.001);        printf("%d\n",t);    }}

 

BJOI2014 想法