题意
对于一个序列,给出一个三元组(a,b,c),代表序列中数值在[a,b]中的数至少有c个,求出序列的最小长度。
Input
The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.
Output
The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.
题解
dis[i]表示[0,i]的数值中的数有多少个,可以得到dis[b]-dis[a-1]>=c-->dis[b]>=dis[a-1]+c 从a-1向b连一条权值为c的边
还有一个隐含条件就是序列每个元素能且只能出现一次,那么0<=dis[i+1]-dis[i]<=1-->dis[i]+0<=dis[i+1],dis[i+1]-1<=dis[i],从i向i+1连一条权值为0的边,从i+1向i连一条权值为-1的边
最后用spfa跑最长路即可
注意:a可能为0,所以读入时对于a,b都+1,这不影响答案。
要记录 最大数值m,最后输出dis[m]
dis要初始化为最小值
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<algorithm> using namespace std; const int maxn=50005; int n,m; int dis[maxn]; int cnt,head[maxn]; struct edge{ int y,next,val; }e[maxn<<2]; void add(int x,int y,int val){ e[++cnt]=(edge){y,head[x],val}; head[x]=cnt; } bool vis[maxn]; queue<int> q; void spfa(){ memset(dis,-0x3f,sizeof(dis)); q.push(0);vis[0]=true; dis[0]=0; while(!q.empty()){ int x=q.front(); q.pop(); vis[x]=false; for(int i=head[x];i;i=e[i].next){ int y=e[i].y,val=e[i].val; if(dis[y]<dis[x]+val){ dis[y]=dis[x]+val; if(!vis[y]) q.push(y),vis[y]=true; } } } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); x++;y++; m=max(m,y); add(x-1,y,z); } for(int i=0;i<m;i++){ add(i,i+1,0); add(i+1,i,-1); } spfa(); printf("%d",dis[m]); }