BJOI2014 想法
3765. 【BJOI2014】想法 (Standard IO)
Time Limits: 4000 ms Memory Limits: 262144 KB Special Judge
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); } }