P1545 [USACO04DEC] Dividing the Path G 题解
P1545 [USACO04DEC] Dividing the Path G 题解
最近开始快刷蓝紫黑了,做完会写题解交上来。
题意
一条长为 \(L(1 \le L \le 10^6 , 2 | L)\) 的线段上,给出 \(N(1 \le N \le 10^3)\) 个可能相交的子段 \([S_i,E_i]\),现要求用若干个长度在 \([2a,2b]\) 中且为偶数的小线段覆盖整个大线段。
要求:
- 整个大线段都要被覆盖。
- 用来覆盖的小线段不相交。
- 每个子段能且仅能被唯一一个小线段覆盖。
- 小线段的范围不能超出大线段。
求出最少用来覆盖的小线段的个数。
分析
这道题暴力 \(O(L^2)\) 是好写的,设 \(dp_i\) 表示覆盖 \([0,i]\) 所需的小线段个数(显然 \(i\) 必须为某个子段的端点),答案明显为 \(dp_L\) ,边界也是显而易见的:\(dp_0=0\) 。
转移有如下式子:
\[dp_i=\min_{j=i-2b,2|j}^{i-2a}(dp_j+1)
\]
虽然数据较水,但我们仍需要考虑正解。
转移方程中,取最小值里的 \(+1\) 可以提出来,所以我们实际上是在求 \(\min dp_j\) 。
我们其实会很容易地发现这其实就是在一段区间里取最小值。
每次转移完当前点的值,我们都会把它当作下次转移时的区间里的一部分。
提炼一下:区间取 \(\min\),单点修改。
线段树可以很方便的处理掉,复杂度 \(O(L\log L)\) 。
AC Code
#include<bits/stdc++.h>
#define int long long
#define rep(I,A,B) for(int I=(A);I<=(B);++I)
#define per(I,A,B) for(int I=(A);I>=(B);--I)
#define el puts("")
#define Yuki return
#define daisuki 0
#define debug puts("SKIRK")
#define none 'N'
#define ed '\n'
#define pc putchar
using namespace std;
using pii=pair<int,int>;
//fastIO start
template<typename T>
void read(T &x){
x=0;bool f=0;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=1;
for(;isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c^48);
if(f)x=-x;
}
template<typename T,typename ...Args>
void read(T &x,Args &...args){
read(x),read(args...);
}
template<typename T>
void write(T x,char ch=' '){
if(x<0)putchar('-'),x=-x;
static short st[70],tp;
do st[++tp]=x%10,x/=10;while(x);
while(tp)putchar(st[tp--]|48);
if(ch!=none)putchar(ch);
}
void writes(string str){
rep(i,0,str.size()-1)putchar(str[i]);
}
void writec(char chs){
putchar(chs);
}
//fastIO end
const int N=1e3+5;
const int L=1e6+5;
const int inf=0x3f3f3f3f;
struct edge{
int s,e;
}p[N];
int n,l,a,b;
bool vis[L];
int dp[L];
struct node{
int l,r,mn;
}tr[L<<2];
void build(int p,int l,int r){
tr[p].l=l;
tr[p].r=r;
tr[p].mn=inf;
if(l==r)return ;
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
int query(int p,int L,int R){
int l=tr[p].l;
int r=tr[p].r;
if(r<L||l>R)return inf;
if(L<=l&&r<=R)return tr[p].mn;
return min(query(p<<1,L,R),query(p<<1|1,L,R));
}
void modify(int p,int L,int v){
int l=tr[p].l;
int r=tr[p].r;
if(r<L||l>L)return ;
if(l==r)return tr[p].mn=v,void();
modify(p<<1,L,v);
modify(p<<1|1,L,v);
tr[p].mn=min(tr[p<<1].mn,tr[p<<1|1].mn);
}
signed main(){
read(n,l,a,b);
rep(i,1,n){
read(p[i].s,p[i].e);
rep(j,p[i].s+1,p[i].e-1)vis[j]=1;
}
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
build(1,0,l);
modify(1,0,0);
for(int i=2;i<=l;i+=2){
if(vis[i])continue;
dp[i]=query(1,max(i-2*b,0ll),i-2*a)+1;
modify(1,i,dp[i]);
// rep(j,a,b){ //暴力转移
// int k=i-j*2;
// if(k<0)continue;
// Min(dp[i],dp[k]+1);
// }
}
if(dp[l]>=inf)dp[l]=-1;
write(dp[l]);
Yuki daisuki;//Yuki真的是太可爱了捏
}
//by oSomiwww

浙公网安备 33010602011771号