POJ1201 Intervals
Intervals
给定n个区间,[ai,bi]这个区间至少选选出ci个整数,求一个集合z,满足每个区间的要求,输出集合z的大小。
题解
令d[i]表示0到i这个区间内至少要选出d[i]个数,那么对于每个[ai,bi],有d[b] - d[ai-1] >= ci,同时隐含的一个条件是0 <= d[i] - d[i-1] <= 1,但是因此d[-1]不能表示,令d[i+1]示0到i这个区间内至少要选出d[i+1]个数,然后d[0] = 0,直接求取最长路就行了。边的存储使用链式向前星,这样效率最高。
因为这不可能是网格图,时间复杂度\(O(k*3n)\)
co int N=5e4+3,M=5e5;
int n,m,d[N];
int Head[N],Edge[M],Leng[M],Next[M],tot;
bool v[N];
il void add(int x,int y,int z){
Edge[++tot]=y,Leng[tot]=z,Next[tot]=Head[x],Head[x]=tot;
}
int main(){
read(n),tot=m=0;
for(int i=1,x,y,z;i<=n;++i){
read(x),read(y),read(z);
add(x,y+1,z),m=max(m,y+1);
}
for(int i=1;i<=m;++i)
add(i-1,i,0),add(i,i-1,-1);
memset(d,0xcf,sizeof d),d[0]=0;
queue<int> q;
q.push(0),v[0]=1;
for(int x;q.size();){
x=q.front(),q.pop(),v[x]=0;
for(int i=Head[x],y;i;i=Next[i])
if(d[y=Edge[i]]<d[x]+Leng[i]){
d[y]=d[x]+Leng[i];
if(!v[y]) q.push(y),v[y]=1;
}
}
printf("%d\n",d[m]);
return 0;
}
另外这题有个显而易见的贪心:这题把数据按b的大小进行从小到大排序。然后每次取最右边的数据,用树状数组维护即可
静渊以有谋,疏通而知事。
浙公网安备 33010602011771号