[NOIP2013]车站分级 解题报告
2015-06-27 10:44
387 查看
妈蛋这道普及组水(神)题搞了我很久。
一、
首先一个非常显然的事情就是每个火车告诉了站与站之间的等级关系,所以拓扑求最长路。
但是发现暴力建边的话最坏可以达到500*500,所以时间复杂度有O(MN2)≈2.5∗108O(MN^2)≈2.5*10^8,常数相当小。。数据水成狗,所以绝对可以过的。
二、
所以我就想到了bitset,把每辆火车做成一个长N的布尔向量,经过为1,不经过为0,第一个车站的左边和最后一个车站的右边补1,。然后对于每个车站,把所有它所在的位为1的向量都&起来,然后扫一遍向量连边。
这样做的时间复杂度可以用long long模拟bitset的时间复杂度来估计,就是O(MN264)≈107O({MN^2 \over 64})≈10^7,常数更小了,实际跑起来其实跟10^6差不多。
三、
然后我看了一个大神的代码,发现原来是有正儿八经的O(NM)的做法的。
我们发现车站之间是比较麻烦的,所以考虑对偶转换!!
我们这样来考虑,比如说我们设火车经过的最低等级的车站为火车的等级,那么火车的等级数=车站的等级数?
按照上面的定义,火车的等级数自然是小于等于车站的等级数的,而如果一个车站不是任何一辆火车的等级,那么就意味着它可以下降或上升它自己的等级直到它是任何一辆火车的等级呢?
但是这样的前提是每一辆车站都至少有一辆火车经过,所以自然我们只要加一辆经过所有车站的火车就可以了。
这样的话,我们只需要求出火车的等级即可了!
但是火车的等级怎么求呢?如果不存在一个车站使得两辆火车都经过它,那么显然这两辆火车之间是没有直接的等级关系的;而如果它们有交的话,那么显然在交集部分经过更多车站的火车的等级应该是更低的,因为低等级的车站会经过所有高等级的车站经过的车站!
一定要注意的地方:
①拓扑求最长路的时候是要求Max!!
②一定要对拍!
code(bitset):
code(对偶转换):
一、
首先一个非常显然的事情就是每个火车告诉了站与站之间的等级关系,所以拓扑求最长路。
但是发现暴力建边的话最坏可以达到500*500,所以时间复杂度有O(MN2)≈2.5∗108O(MN^2)≈2.5*10^8,常数相当小。。数据水成狗,所以绝对可以过的。
二、
所以我就想到了bitset,把每辆火车做成一个长N的布尔向量,经过为1,不经过为0,第一个车站的左边和最后一个车站的右边补1,。然后对于每个车站,把所有它所在的位为1的向量都&起来,然后扫一遍向量连边。
这样做的时间复杂度可以用long long模拟bitset的时间复杂度来估计,就是O(MN264)≈107O({MN^2 \over 64})≈10^7,常数更小了,实际跑起来其实跟10^6差不多。
三、
然后我看了一个大神的代码,发现原来是有正儿八经的O(NM)的做法的。
我们发现车站之间是比较麻烦的,所以考虑对偶转换!!
我们这样来考虑,比如说我们设火车经过的最低等级的车站为火车的等级,那么火车的等级数=车站的等级数?
按照上面的定义,火车的等级数自然是小于等于车站的等级数的,而如果一个车站不是任何一辆火车的等级,那么就意味着它可以下降或上升它自己的等级直到它是任何一辆火车的等级呢?
但是这样的前提是每一辆车站都至少有一辆火车经过,所以自然我们只要加一辆经过所有车站的火车就可以了。
这样的话,我们只需要求出火车的等级即可了!
但是火车的等级怎么求呢?如果不存在一个车站使得两辆火车都经过它,那么显然这两辆火车之间是没有直接的等级关系的;而如果它们有交的话,那么显然在交集部分经过更多车站的火车的等级应该是更低的,因为低等级的车站会经过所有高等级的车站经过的车站!
一定要注意的地方:
①拓扑求最长路的时候是要求Max!!
②一定要对拍!
code(bitset):
[code]#include<iostream> using namespace std; #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> inline void in(int &x){ char c=getchar(); x=0; while(c<'0'||c>'9')c=getchar(); for(;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0'); } int l[1005],r[1005]; #include<bitset> bitset<1005> be[1005],btmp; int next[1000005],ptr[1005],succ[1000005]; int stack[1005],level[1005],ru[1005]; int main(){ freopen("level2013.in","r",stdin); freopen("level_TA.out","w",stdout); int n,m,i,j,stop,s; in(n),in(m); for(i=m;i--;){ in(s); in(l[i]); for(--s;--s;){ in(stop); be[i][stop]=1; } in(r[i]); for(j=l[i];j;--j)be[i][j]=1; for(j=r[i];j<=n;++j)be[i][j]=1; } int etot=1; for(i=n;i;--i){ btmp.set(); for(j=m;j--;) if(l[j]<=i&&i<=r[j]&&be[j][i]){ //cout<<"Get:"<<j<<endl; btmp&=be[j]; } for(j=n;j;--j) if(~btmp[j]){ next[etot]=ptr[i],ptr[i]=etot,succ[etot++]=j; //cout<<i<<"->"<<j<<":"<<ptr[i]<<"->"<<next[etot-1]<<endl; ++ru[j]; } } int top=0; for(i=n;i;--i) if(ru[i]==0){ stack[top++]=i; level[i]=1; //cout<<"First into stack:"<<i<<endl; } int nowlevel; while(top--){ nowlevel=level[stack[top]]; //cout<<"----"<<stack[top]<<"-----\n"; for(i=ptr[stack[top]];i;i=next[i]){ level[succ[i]]=max(level[succ[i]],nowlevel+1); //cout<<i<<":"<<nowlevel+1<<"->"<<succ[i]<<endl; if(--ru[succ[i]]==0)stack[top++]=succ[i]; } } printf("%d\n",*max_element(level+1,level+n+1)); }
code(对偶转换):
[code]#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> using namespace std; inline void in(int &x){ char c=getchar(); while(c<'0'||c>'9')c=getchar(); x=0; for(;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0'); } int num[1005][1005],stop[1005][1005]; int stack[1005]; int next[1000005],ptr[1005],succ[1000005],ru[1005],etot=1; int level[1005]; inline void addedge(int u,int v){ next[etot]=ptr[u],ptr[u]=etot,++ru[v],succ[etot++]=v; } int main(){ freopen("level2013.in","r",stdin); freopen("level2013.out","w",stdout); int n,m,i,j,k,tmp; in(n),in(m); ++m; for(i=n;i;--i)num[0][i]=stop[0][i]=i; stop[0][0]=n; for(i=m;--i;){ in(stop[i][0]); for(j=1,k=1;j<=stop[i][0];++j) for(in(stop[i][j]);k<stop[i][j];++k) num[i][k]=j-1; --j; while(k<=n)num[i][k++]=j; } int l,r; for(i=m;i--;) for(j=i;j--;){ l=max(stop[i][1],stop[j][1])-1; r=min(stop[i][stop[i][0]],stop[j][stop[j][0]]); if(l<=r) if(num[i][r]-num[i][l]>num[j][r]-num[j][l])addedge(i,j); else if(num[i][r]-num[i][l]<num[j][r]-num[j][l])addedge(j,i); } int top=0; for(i=m;i--;) if(!ru[i]){ stack[top++]=i; level[i]=1; } int nowlevel; while(top--){ nowlevel=level[stack[top]]+1; for(i=ptr[stack[top]];i;i=next[i]){ level[succ[i]]=max(level[succ[i]],nowlevel); if(!--ru[succ[i]])stack[top++]=succ[i]; } } printf("%d\n",*max_element(level,level+m)); }
相关文章推荐
- ASP.NET项目中使用CKEditor +CKFinder 实现上传图片
- jquery学习之-普通选择器
- 感知中国·俄罗斯行”开幕式在圣彼得堡举行 刘..
- 开发板tftp下载文件
- 淘宝新闻
- 日乒赛-马龙爆冷止步次轮 朱雨玲陈梦率先进8强
- C++ 实现MST kruskal's algorithm
- 6000万欧元英超热钱滋润德甲 菲尔米诺创新高
- 视差滚动插件Stellar.js
- windows下动态链接库的创建和使用
- 4.85亿!将到账 米兰领跑巴卡追逐战再追一猛将
- Android 蓝牙学习
- iOS开发系列--并行开发其实很容易
- Cocoa pods 管理第三方框架
- (5)风色从零单排《C++ Primer》 const,typedef,auto,decltype
- iOS系类教程之用instruments来检验你的app
- linux下查看文件夹及文件大小
- ubuntu 包常用安装,卸载命令
- Jboss7类加载器
- VC创建线程