[Usaco2006 Open]County Fair Events 参加节日庆祝

原题链接https://www.lydsy.com/JudgeOnline/problem.php?id=1664

可以发现的是,如果参加了节日\(i\)之后可以参加节日\(j\),当且仅当\(i\)节日的结束时间\(l[i]\)小于等于\(j\)节日的开始时间\(t[j]\)。那么我们对于每个\(i\),可以从\(i\)出发向每个合法的\(j\)连一条边,表示参加完\(i\)之后可以接着参加\(j\)

题目要求最多参加几场节日,那么我们设边权为1,在我们建出的\(DAG\)上算出最长路的长度就是答案。那么我们可以建一个超级源,用拓扑排序进行\(dp\)

建图的时间复杂度最坏为\(O(\frac{N(N-1)}{2})\),图的规模也是\(\frac{N(N-1)}{2}\),所以拓扑排序的复杂度和建图一致。

不过我们可以整一个玄学优化:我们可以不用对于每个\(i\)都枚举完\(1\)~\(n\)所有节日。我们先把节日按照开始时间\(t\)从小到大进行排序,然后对于第\(i\)个节日,我们二分查找第一个开始时间大于等于\(i\)的结束时间的节日\(j\),那么我们把\(i\)连向\(j\)~\(n\)即可。这样一般就不用枚举完1~n所有数。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#define maxn 10010
using namespace std;
 
inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
 
struct node{ int t,l,id; }a[maxn];
vector<int> to[maxn];
int n,tmp[maxn];
int ind[maxn],dp[maxn],ans;
 
inline bool cmp(const node &x,const node &y){ return x.t<y.t; }
 
inline int binary(const int &val){
    if(a[n].t<val) return -1;
    int l=1,r=n,mid;
    while(l<r){
        mid=l+r>>1;
        if(a[mid].t<val) l=mid+1;
        else r=mid;
    }
    return l;
}
 
queue<int> q;
inline void topo(){
    q.push(0),dp[0]=0;
    while(q.size()){
        int u=q.front(); q.pop();
        for(register int i=0;i<to[u].size();i++){
            int v=to[u][i];
            dp[v]=max(dp[v],dp[u]+1),ind[v]--;
            if(!ind[v]) q.push(v);
        }
    }
}
 
int main(){
    n=read();
    for(register int i=1;i<=n;i++) a[i].t=read(),a[i].l=read(),a[i].id=i;
    sort(a+1,a+1+n,cmp);
     
    for(register int i=1;i<=n;i++){
        int end=a[i].l+a[i].t;
        int j=binary(end);
        if(j==-1) continue;
        for(register int k=j;k<=n;k++){
            to[a[i].id].push_back(a[k].id),ind[a[k].id]++;
        }
    }
    for(register int i=1;i<=n;i++) to[0].push_back(i),ind[i]++;
     
    topo();
    for(register int i=1;i<=n;i++) ans=max(ans,dp[i]);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akura/p/11309779.html
今日推荐