[IOI2011]Race
Posted zhy12138
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[IOI2011]Race相关的知识,希望对你有一定的参考价值。
毕竟是人生第一道IOI(现在已经挂了又A了~~),就认真写一写吧。
竟然有爆栈这种操作(亏我花了一个多小时优化时间以为RE是TLE)
题面一看就是淀粉质。(感觉好裸)
以下是同学的挂掉做法
1 #include<bits/stdc++.h> 2 using namespace std; 3 template<class T> 4 inline void read(T &a) 5 { 6 T s = 0, w = 1; 7 char c = getchar(); 8 while(c < ‘0‘ || c > ‘9‘) 9 { 10 if(c == ‘-‘) w = -1; 11 c = getchar(); 12 } 13 while(c >= ‘0‘ && c <= ‘9‘) 14 { 15 s = (s << 1) + (s << 3) + (c ^ 48); 16 c = getchar(); 17 } 18 a = s*w; 19 } 20 struct edge{ 21 int from,to,cost,net; 22 edge(int f = 0, int t = 0, int c = 0, int n = 0) 23 { 24 from = f; 25 to = t; 26 cost = c; 27 net = n; 28 } 29 }edges[101010]; 30 int head[101010],tot,k,n; 31 void add(int x, int y, int c) 32 { 33 edges[++tot] = edge(x,y,c,head[x]); 34 head[x] = tot; 35 } 36 int root = 0; 37 int vis[101010],mx[10101],size[101010],S; 38 void find(int x, int fa) 39 { 40 size[x] = 1;mx[x] = 0; 41 for (int i = head[x];i;i = edges[i].net) 42 { 43 edge v = edges[i]; 44 if(vis[v.to] || v.to == fa) continue; 45 find(v.to,x); 46 size[x] += size[v.to]; 47 mx[x] = max(mx[x],size[v.to]); 48 } 49 mx[x] = max(mx[x],S-size[x]); 50 if(mx[x] < mx[root]) 51 { 52 root = x; 53 } 54 } 55 int cnt,dis[10101],deep[101010]; 56 int minn = 0x3f3f3f3f; 57 int ans = 0; 58 void get_dis(int x,int fa,int len,int k) 59 { 60 dis[++cnt] = len; 61 deep[cnt] = k; 62 for (int i = head[x];i;i = edges[i].net) 63 { 64 edge v = edges[i]; 65 if(vis[v.to]||v.to == fa) continue; 66 get_dis(v.to,x,len+v.cost,k+1); 67 } 68 } 69 void solve(int x,int len, int pp) 70 { 71 cnt = 0; 72 get_dis(x,0,len,0); 73 sort(dis+1,dis+1+cnt); 74 int l = 1,r = cnt; 75 while(l <= r) 76 { 77 if(dis[l] + dis[r] == k) 78 { 79 ans += pp; 80 if(deep[l] + deep[r] < minn) 81 { 82 minn = deep[l] + deep[r]; 83 } 84 break; 85 } 86 if(dis[l] + dis[r] < k) l++; 87 if(dis[l] + dis[r] > k) r--; 88 89 } 90 /*for (int i = 1; i <= cnt; i++) 91 { 92 for (int j = 1; j <= cnt; j++) 93 { 94 if(dis[i] + dis[j] == k) ans += pp; 95 } 96 }*/ 97 } 98 void Divide(int x) 99 { 100 solve(x,0,1); 101 vis[x] = 1; 102 for (int i = head[x];i;i = edges[i].net) 103 { 104 edge v = edges[i]; 105 if(vis[v.to]) continue; 106 solve(v.to,v.cost,-1); 107 S = size[v.to]; root = 0; 108 find(v.to,x); 109 // printf("%d ",root); 110 Divide(root); 111 } 112 } 113 int main() 114 { 115 read(n); read(k); 116 for (int i = 1; i < n; i++) 117 { 118 int x,y,z; 119 read(x); read(y); read(z); 120 x++;y++; 121 add(x,y,z); 122 add(y,x,z); 123 } 124 root = 0; 125 mx[root] = n+1; 126 S = n; 127 find(1,0); 128 //printf("%d ",root); 129 Divide(root); 130 printf("%d ",ans == 0? -1 : minn); 131 return 0; 132 }
该算法挂掉的主要原因在于使用计数器记录最小值时,一个元素无法处理错误路径这种骚操作。
于是蒟蒻的我想到了开一个大数组来计数(这TM不就是桶排吗)
于是我就自信地打上了如下代码
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cmath> 5 #include<iomanip> 6 #include<cstring> 7 #include<algorithm> 8 #include<ctime> 9 #define ll long long 10 using namespace std; 11 inline ll read() 12 { 13 ll kkk=0; 14 int x=1; 15 char c=getchar(); 16 while(c<‘0‘ || c>‘9‘) 17 { 18 if(c==‘-‘) 19 x=-1; 20 c=getchar(); 21 } 22 while(c>=‘0‘ && c<=‘9‘) 23 kkk=(kkk<<3)+(kkk<<1)+(c-‘0‘),c=getchar(); 24 return kkk*x; 25 } 26 struct sb 27 { 28 int to,l,nextn; 29 }a[200001]; 30 int n,k,num,maxn,root,z,tot,head[200001],size[200001],maxsize[200001],ans[200001],dis[200001][2]; 31 char pd[200001]; 32 inline int ADD(int from,int to,int l) 33 { 34 ++tot; 35 a[tot].to=to,a[tot].l=l,a[tot].nextn=head[from],head[from]=tot; 36 } 37 inline int find(int u,int fa) 38 { 39 size[u]=1,maxsize[u]=0; 40 for(register int i=head[u];i!=0;i=a[i].nextn) 41 { 42 int v=a[i].to; 43 if(v==fa || pd[v]==1) 44 continue; 45 find(v,u); 46 size[u]+=size[v],maxsize[u]=max(maxsize[u],size[v]); 47 } 48 maxsize[u]=max(maxsize[u],z-size[u]); 49 if(maxsize[u]<maxn) 50 root=u,maxn=maxsize[u]; 51 } 52 inline int run(int u,int fa,int l,int deep) 53 { 54 dis[++num][0]=l,dis[num][1]=deep; 55 for(register int i=head[u];i!=0;i=a[i].nextn) 56 { 57 int v=a[i].to; 58 if(v==fa || pd[v]==1) 59 continue; 60 run(v,u,l+a[i].l,deep+1); 61 } 62 } 63 inline int fun(int Root) 64 { 65 pd[Root]=1; 66 num=0; 67 run(Root,-1,0,0); 68 for(register int i=1;i<=num;++i) 69 for(register int j=i;j<=num;++j) 70 if(dis[i][0]+dis[j][0]==k) 71 ++ans[dis[i][1]+dis[j][1]]; 72 for(register int i=head[Root];i!=0;i=a[i].nextn) 73 { 74 int v=a[i].to; 75 if(pd[v]==1) 76 continue; 77 num=0; 78 run(v,Root,a[i].l,1); 79 for(register int j=1;j<=num;++j) 80 for(register int w=j;w<=num;++w) 81 if(dis[j][0]+dis[w][0]==k) 82 --ans[dis[j][1]+dis[w][1]]; 83 maxn=0x7f7f7f7f,root=-1,z=size[v]; 84 find(v,Root); 85 fun(root); 86 } 87 } 88 int main() 89 { 90 n=read(),k=read(); 91 for(register int i=1;i<n;++i) 92 { 93 int u=read(),v=read(),k=read(); 94 ADD(u,v,k),ADD(v,u,k); 95 } 96 maxn=0x7f7f7f7f,root=-1,z=n; 97 find(0,-1); 98 fun(root); 99 for(register int i=0;i<=n;++i) 100 if(ans[i]!=0) 101 { 102 printf("%d ",i); 103 return 0; 104 } 105 putchar(‘-‘); 106 putchar(‘1‘); 107 putchar(‘ ‘); 108 return 0; 109 }
和之前那份代码明显码风不同吧
结果我尴尬地只拿了10分,蒟蒻的我开始沉思————这么高级的方法怎么会挂呢???(WTF,除了点分治高级外就全是枚举好吧)
其实我只是想检查算法正确性玩玩而已(啊啊,别打)
以上代码挂掉的主要原因是计数那一段太慢了,没错就是下面这一段
1 num=0; 2 run(Root,-1,0,0); 3 for(register int i=1;i<=num;++i) 4 for(register int j=i;j<=num;++j) 5 if(dis[i][0]+dis[j][0]==k) 6 ++ans[dis[i][1]+dis[j][1]];
于是我排了个序,用用两个指针找了下合法方案,并用last记录没次二号指针的最大位置+1就过了
PS:注意路径长度之和完全可以相等,所以找到合法方案后要向下循环求解应该会被卡成跟之前那段一样的时间(离散化可以优化)
1 num=0; 2 run(Root,-1,0,0); 3 sort(dis+1,dis+num+1,cmp); //为了排序,我把之前的dis[][0]和dis[][1]放在了struct里面 4 int last=1; 5 for(;last<=num & dis[1].l+dis[last].l<=k;++last); //这里有个分号!!! 6 for(register int i=1;i<=num & dis[i].l*2<k;++i) 7 { 8 int j=last-1; 9 while(j>=i) 10 { 11 int P=dis[i].l+dis[j].l; 12 if(P<=k) 13 { 14 last=j+1; 15 if(P==k) 16 { 17 ++ans[dis[i].deep+dis[j].deep]; 18 while(dis[j-1].l==dis[j].l & j>i) 19 --j,++ans[dis[i].deep+dis[j].deep]; 20 } 21 break; 22 } 23 --j; 24 } 25 }
不过我觉得last的初始化太暴力,就用二分查找小优化了以下,那都是后话了
好吧接下来是AC代码(至少以前是的现在也是)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cmath> 5 #include<iomanip> 6 #include<cstring> 7 #include<algorithm> 8 #include<ctime> 9 #define ll long long 10 using namespace std; 11 inline int read() 12 { 13 int kkk=0; 14 int x=1; 15 char c=getchar(); 16 while(c<‘0‘ || c>‘9‘) 17 { 18 if(c==‘-‘) 19 x=-1; 20 c=getchar(); 21 } 22 while(c>=‘0‘ && c<=‘9‘) 23 kkk=(kkk<<3)+(kkk<<1)+(c-‘0‘),c=getchar(); 24 return kkk*x; 25 } 26 struct sb 27 { 28 int to,l,nextn; 29 }a[400001]; 30 int n,k,num,maxn,root,z,tot,head[400001],size[400001],maxsize[400001],ans[400001]; 31 struct tmd 32 { 33 int l,deep; 34 }dis[400001]; 35 char pd[400001]; 36 inline int cmp(tmd x,tmd y) 37 { 38 return x.l<y.l; 39 } 40 inline int ADD(int from,int to,int l) 41 { 42 ++tot; 43 a[tot].to=to,a[tot].l=l,a[tot].nextn=head[from],head[from]=tot; 44 } 45 inline int find(int u,int fa) 46 { 47 size[u]=1,maxsize[u]=0; 48 for(register int i=head[u];i;i=a[i].nextn) 49 { 50 int v=a[i].to; 51 if(v==fa | pd[v]) 52 continue; 53 find(v,u); 54 size[u]+=size[v],maxsize[u]=(maxsize[u]>size[v]?maxsize[u]:size[v]); 55 } 56 maxsize[u]=(maxsize[u]>z-size[u]?maxsize[u]:z-size[u]); 57 if(maxsize[u]<maxn) 58 root=u,maxn=maxsize[u]; 59 } 60 inline int run(int u,int fa,int l,int deep) 61 { 62 dis[++num].l=l,dis[num].deep=deep; 63 for(register int i=head[u];i;i=a[i].nextn) 64 { 65 int v=a[i].to; 66 if(v==fa | pd[v]) 67 continue; 68 run(v,u,l+a[i].l,deep+1); 69 } 70 } 71 inline int fun(int Root) 72 { 73 pd[Root]=1,num=0,run(Root,-1,0,0),sort(dis+1,dis+num+1,cmp); 74 int last,l=1,r=num; 75 while(l<r) 76 { 77 int mid=(l+r)/2; 78 if(dis[1].l+dis[mid].l<=k) 79 l=mid+1; 80 else 81 r=mid; 82 } 83 last=l; 84 if(last==num & dis[1].l+dis[last].l<=k) 85 ++last; 86 for(register int i=1;i<=num & dis[i].l*2<k;++i) 87 { 88 int j=last-1; 89 while(j>=i) 90 { 91 int P=dis[i].l+dis[j].l; 92 if(P<=k) 93 { 94 last=j+1; 95 if(P==k) 96 { 97 ++ans[dis[i].deep+dis[j].deep]; 98 while(dis[j-1].l==dis[j].l & j>i) 99 --j,++ans[dis[i].deep+dis[j].deep]; 100 } 101 break; 102 } 103 --j; 104 } 105 } 106 for(register int i=head[Root];i;i=a[i].nextn) 107 { 108 int v=a[i].to; 109 if(pd[v]) 110 continue; 111 num=0,run(v,Root,a[i].l,1),sort(dis+1,dis+num+1,cmp); 112 l=1,r=num; 113 while(l<r) 114 { 115 int mid=(l+r)/2; 116 if(dis[1].l+dis[mid].l<=k) 117 l=mid+1; 118 else 119 r=mid; 120 } 121 last=l; 122 if(last==num & dis[1].l+dis[last].l<=k) 123 ++last; 124 for(register int j=1;j<=num & dis[j].l*2<k;++j) 125 { 126 int w=last-1; 127 while(w>=j) 128 { 129 int P=dis[j].l+dis[w].l; 130 if(P<=k) 131 { 132 last=w+1; 133 if(P==k) 134 { 135 --ans[dis[j].deep+dis[w].deep]; 136 while(dis[w-1].l==dis[w].l & w>j) 137 --w,--ans[dis[j].deep+dis[w].deep]; 138 } 139 break; 140 } 141 --w; 142 } 143 } 144 maxn=0x7f7f7f7f,root=-1,z=size[v],find(v,Root),fun(root); 145 } 146 } 147 int main() 148 { 149 n=read(),k=read(); 150 for(register int i=1;i<n;++i) 151 { 152 int u=read(),v=read(),k=read(); 153 ADD(u,v,k),ADD(v,u,k); 154 } 155 maxn=0x7f7f7f7f,root=-1,z=n; 156 find(0,-1),fun(root); 157 for(register int i=0;i<=n;++i) 158 if(ans[i]) 159 { 160 printf("%d ",i); 161 return 0; 162 } 163 putchar(‘-‘); 164 putchar(‘1‘); 165 putchar(‘ ‘); 166 return 0; 167 }
后记:
洛谷评测姬更新以后空间好像变少了,所以我的栈空间被卡爆了,大数据连找重心都跑不过。所以还需要打手动膜模拟栈来优化,但太麻烦了。(2018.8)
我今天好像发现把能换int类型的函数换成void就能过了。(2018.10.30)
以上是关于[IOI2011]Race的主要内容,如果未能解决你的问题,请参考以下文章