POJ 1201
CH POJ1201
Description
You are given n closed, integer intervals [ai, bi] and n integers c1, …, cn.
Write a program that:
reads the number of intervals, their end points and integers c1, …, cn from the standard input,
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,…,n,
writes the answer to the standard output.
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.
Sample Input
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
Sample Output
6
Source
Southwestern Europe 2002
嗯,看完书上的文字题解,不出十分钟敲完,然后。。。。。。。我承认,我把“负权”两个字忘掉了,傻子一般地敲了一个 D i j k s t r a Dijkstra Dijkstra,然后半天跑不出来答案,再好好看书后,猛然发现,这是有负权的。。。。。。。。。。
这道题其实就是让我们在 0 ∼ 50 , 000 0\sim50,000 0∼50,000之间选出尽量少的数,使得每一个 [ a i , b i ] [a_{i},b_{i}] [ai,bi]内至少有 c i c_{i} ci个数被选择。
设 s [ k ] s[k] s[k]表示 0 ∼ k 0\sim k 0∼k之间有几个数字被选,很明显, s [ b i ] − s [ a i − 1 ] > = c i s[b_{i}]-s[a_{i}-1]>=c_{i} s[bi]−s[ai−1]>=ci。这就很明确地告诉我们这是一个差分约束系统的模型了。
当然,秉着差分约束经常搞些隐含条件的规则,我们还是要去再想想的,毕竟这样才能保证求出的解是合法的。
然后我们就可以发现(你管我是怎么发现的QWQ):
1 . s [ k ] − s [ k − 1 ] > = 0 .s[k]-s[k-1]>=0 .s[k]−s[k−1]>=0。 0 ∼ k 0 \sim k 0∼k中所选取的整数肯定要比 0 ∼ k − 1 0\sim k-1 0∼k−1中选取的整数多。
2. s [ k ] − s [ k − 1 ] < = 1 s[k]-s[k-1]<=1 s[k]−s[k−1]<=1。因为每个数最多只能被选择一次。也可变形成为 s [ k − 1 ] − s [ k ] > = − 1 s[k-1]-s[k]>=-1 s[k−1]−s[k]>=−1。
因此,我们把 0 ∼ 50001 0 \sim 50001 0∼50001这 50002 50002 50002个整数分别作为图中的节点,从每个 k − 1 k-1 k−1到 k k k连一条长度为 0 0 0的有向边, k k k到 k − 1 k-1 k−1连一条长度为 − 1 -1 −1的有向边,从每个 a i a_{i} ai到 b i + 1 b_{i}+1 bi+1连一条长度为ci的有向边。
最后,令 s [ 0 ] = 0 s[0]=0 s[0]=0,以 0 0 0为起点跑单源最长路。因为本题保证了 1 < = c i < = b i − a i + 1 1 <= c_{i} <= b_{i} - a_{i}+1 1<=ci<=bi−ai+1,所以本题中没有正环,差分约束系统一定有解。求完最长路后, s [ 50001 ] = d i s t [ 50001 ] s[50001]=dist[50001] s[50001]=dist[50001]就是本题的答案。(到这里,也就知道了 s [ ] s[] s[]就是 d i s t [ ] dist[] dist[]了,而且,《算阶》上的因为要从 − 1 -1 −1开始跑,我搞不定,就把他们全都加一了。)。
#include
using namespace std;
const int maxn=1e7+10;
template<typename T>inline void read(T &x)
{
x=0;
T f=1,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
int ver[maxn],edge[maxn],Next[maxn],head[maxn],len;
inline void add(int x,int y,int z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
int dist[maxn];
bool vis[maxn];
inline void Dijkstra(int s)
{
queue<int>q;
memset(dist,-1,sizeof(dist));
memset(vis,0,sizeof(vis));
dist[s]=0,vis[s]=1;
q.push(s);
while (!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i],z=edge[i];
if (dist[y]<dist[x]+z)
{
dist[y]=dist[x]+z;
if (!vis[y]) q.push(y),vis[y]=1;
}
}
}
}
int main()
{
int n,mx=-1;
read(n);
for (int i=1;i<=n;++i)
{
int x,y,z;
read(x);read(y);read(z);
add(x,y+1,z);
mx=max(y,mx);
}
++mx;
for (int i=1;i<=mx;++i)
add(i-1,i,0),add(i,i-1,-1);
Dijkstra(0);
printf("%d\n",dist[mx]);
return 0;
}