[NOIP2013]车站分级 解题报告

妈蛋这道普及组水(神)题搞了我很久。

一、

首先一个非常显然的事情就是每个火车告诉了站与站之间的等级关系,所以拓扑求最长路。

但是发现暴力建边的话最坏可以达到500*500,所以时间复杂度有O(MN2)≈2.5?108,常数相当小。。数据水成狗,所以绝对可以过的。

二、

所以我就想到了bitset,把每辆火车做成一个长N的布尔向量,经过为1,不经过为0,第一个车站的左边和最后一个车站的右边补1,。然后对于每个车站,把所有它所在的位为1的向量都&起来,然后扫一遍向量连边。

这样做的时间复杂度可以用long long模拟bitset的时间复杂度来估计,就是O(MN264)≈107,常数更小了,实际跑起来其实跟10^6差不多。

三、

然后我看了一个大神的代码,发现原来是有正儿八经的O(NM)的做法的。

我们发现车站之间是比较麻烦的,所以考虑对偶转换!!

我们这样来考虑,比如说我们设火车经过的最低等级的车站为火车的等级,那么火车的等级数=车站的等级数?

按照上面的定义,火车的等级数自然是小于等于车站的等级数的,而如果一个车站不是任何一辆火车的等级,那么就意味着它可以下降或上升它自己的等级直到它是任何一辆火车的等级呢?

但是这样的前提是每一辆车站都至少有一辆火车经过,所以自然我们只要加一辆经过所有车站的火车就可以了。

这样的话,我们只需要求出火车的等级即可了!

但是火车的等级怎么求呢?如果不存在一个车站使得两辆火车都经过它,那么显然这两辆火车之间是没有直接的等级关系的;而如果它们有交的话,那么显然在交集部分经过更多车站的火车的等级应该是更低的,因为低等级的车站会经过所有高等级的车站经过的车站!

一定要注意的地方:

①拓扑求最长路的时候是要求Max!!

②一定要对拍!

code(bitset):

#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(对偶转换):

#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));
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-29 09:43:32

[NOIP2013]车站分级 解题报告的相关文章

&lt;NOIP2013 花匠&gt; 新人解题报告

本来按照老师的要求,我学OI的第一份解题报告应是在寒假完成的关于数据结构的基础题,但由于身体原因当时未能完成,那么就在省选赛前临时写几篇吧-- 题目描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致. 具体而言,栋栋的花的高度可以看成一列整数?1, ?2, - , ?n.设当一部分花被移走后,剩下的花的高度依次为g1, g2, - , gm,则栋栋希望下面两个条

NOIP2013 车站分级

描述 一条单向的铁路线上,依次有编号为 1, 2, ..., n 的 n 个火车站.每个火车站都有一个级别,最低为 1 级.现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x,则始发站.终点站之间所有级别大于等于火车站 x 的都必须停靠.(注意:起始站和终点站自然也算作事先已知需要停靠的站点)例如,下表是 5 趟车次的运行情况.其中,前 4 趟车次均满足要求,而第 5 趟车次由于停靠了 3 号火车站(2 级)却未停靠途经的 6 号火车站(亦为 2 级)而不满足要求

【noip2013】d2解题报告

d2我就做了1个小时,因为实在不想写华容道了 t1:积木大赛 这个题很明显,如果前一个比现在的一个矮,令答案加上高度差,否则就不管,因为假如说现在的高度小于等于前一个的时候,就可以与上一个一起操作 #include<iostream> #include<cstring> #include<cstdio> using namespace std; int n,a[100010],ans; int main() { scanf("%d",&n);

2016.7.12 NOIP2013提高组 day2解题报告(未完成版)

考试马不停蹄地到来,昨天的程序还没改完,今天又考了day2,虽然没有昨天那么懵逼,但还是不尽如人意,现在还没讲题,我打算先自己看一次解题报告,争取加深理解,毕竟一位前辈说过,做一套题的质量取决于题本身的质量和你思考的程度. 考试总结: 1.数据分析推测可行算法很重要,要灵活掌握常用算法的时间复杂度: 2.对拍的方式要熟练,写对拍耗费的时间过多: 3.要加强代码实现的能力,比较突出的表现就是写200-300行多函数模拟或搜索的能力: 4.不要急于写过不完的程序,要多拿一点时间来分析数据,样例不够还

习题:codevs 1035 火车停留解题报告

本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润,让你来求一种安排方法,使得车站收益最大,并输出收益值. 蒟蒻的思路是这样的: 一眼看出:最大费用最大流(MCMF)显然cost:表示车站收益然后……以车站为点建立图求流?同一个车站可能经过好几辆火车……,貌似很麻烦……:那么以什么建图.连边,还有怎么连?貌似有点类似于方格取数2之中的拆点……:那么

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

hdu 1541 Stars 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 题目意思:有 N 颗星星,每颗星星都有各自的等级.给出每颗星星的坐标(x, y),它的等级由所有比它低层(或者同层)的或者在它左手边的星星数决定.计算出每个等级(0 ~ n-1)的星星各有多少颗. 我只能说,题目换了一下就不会变通了,泪~~~~ 星星的分布是不是很像树状数组呢~~~没错,就是树状数组题来滴! 按照题目输入,当前星星与后面的星星没有关系.所以只要把 x 之前的横坐标加起来就可以了

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共