[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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/akura/p/11309779.html