[NOIP2013]车站分级 解题报告

妈蛋这道普及组水(神)题搞了我非常久。
一、
首先一个非常显然的事情就是每一个火车告诉了站与站之间的等级关系,所以拓扑求最长路。
可是发现暴力建边的话最坏能够达到500*500,所以时间复杂度有O(MN2)2.5108,常数相当小。

。数据水成狗,所以绝对能够过的。
二、
所以我就想到了bitset,把每辆火车做成一个长N的布尔向量。经过为1,不经过为0,第一个车站的左边和最后一个车站的右边补1,。

然后对于每一个车站,把全部它所在的位为1的向量都&起来,然后扫一遍向量连边。
这样做的时间复杂度能够用long long模拟bitset的时间复杂度来预计。就是OMN264107,常数更小了。实际跑起来事实上跟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]<<"-----
";
        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
",*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
",*max_element(level,level+m));
}
原文地址:https://www.cnblogs.com/blfbuaa/p/6991810.html