分析:
看到这道题,我的反应就是线性规划
我一开始把问题抽象成:
给出一条数轴和n个区间,在数轴上选取尽量少的数,使得每个区间内都有K个数被选中
经过转化后,这道题就和bzoj3550一样了
但是这道题的数据范围有点大,所以我们要另辟蹊径
设
dis[i]
d
i
s
[
i
]
表示
1−i
1
−
i
中广告牌的数量,那么区间
[a,b]
[
a
,
b
]
内广告牌的数量就是:
dis[b]−dis[a−1]
d
i
s
[
b
]
−
d
i
s
[
a
−
1
]
那么我们就可以得到一些不等式关系:
dis[b]−dis[a−1]>=K,dis[b]>=dis[a−1]+K
d
i
s
[
b
]
−
d
i
s
[
a
−
1
]
>=
K
,
d
i
s
[
b
]
>=
d
i
s
[
a
−
1
]
+
K
如果区间长度不足K,则:
dis[b]−dis[a−1]=c,c=b−a+1
d
i
s
[
b
]
−
d
i
s
[
a
−
1
]
=
c
,
c
=
b
−
a
+
1
,即
dis[b]−dis[a−1]>=c,dis[b]>=dis[a−1]+c
d
i
s
[
b
]
−
d
i
s
[
a
−
1
]
>=
c
,
d
i
s
[
b
]
>=
d
i
s
[
a
−
1
]
+
c
dis[b]−dis[a−1]<=c,dis[a−1]>=dis[b]−c
d
i
s
[
b
]
−
d
i
s
[
a
−
1
]
<=
c
,
d
i
s
[
a
−
1
]
>=
d
i
s
[
b
]
−
c
又因为每个位置只能设置一个广告牌
0<=dis[b]−dis[a−1]<=1
0
<=
d
i
s
[
b
]
−
d
i
s
[
a
−
1
]
<=
1
有了上面的不等式,我们就可以用差分约束解决了
tip
给出的约束条件都是 >= >= ,因此我们可以跑一遍最长路
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int INF=1e9;
const int N=1010;
const int o=10001;
struct node {
int y,v,nxt;
};
node way[2000000];
int K,n,st[2*o+10],tot=0,dis[2*o+10],cnt[2*o+10],mx,mn;
bool in[2*o+10];
void add(int u,int w,int z)
{
tot++;
way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}
bool spfa()
{
int s=mn;
memset(dis,128,sizeof(dis));
memset(in,0,sizeof(in));
queue<int> Q;
Q.push(s); in[s]=1; dis[s]=0;
while (!Q.empty())
{
int now=Q.front(); Q.pop();
in[now]=0;
for (int i=st[now];i;i=way[i].nxt)
if (dis[way[i].y]<dis[now]+way[i].v)
{
dis[way[i].y]=dis[now]+way[i].v;
if (!in[way[i].y])
{
in[way[i].y]=1;
Q.push(way[i].y);
}
}
}
return 1;
}
void print()
{
printf("%d\n",dis[mx]);
for (int i=mn;i<=mx;i++)
if (dis[i-1]==dis[i]-1) printf("%d\n",i-o);
}
int main()
{
mx=-INF,mn=INF;
scanf("%d%d",&K,&n);
for (int i=1;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if (a>b) swap(a,b);
a=a-1+o; b+=o;
mx=max(mx,b); mn=min(mn,a);
if (b-a>=K) add(a,b,K);
else add(b,a,a-b),add(a,b,b-a);
}
for (int i=mn;i<mx;i++) add(i+1,i,-1),add(i,i+1,0);
spfa();
print();
return 0;
}