P10052 [CCO 2022] Double Attendance Sol

题目链接

思路

考虑DP。

注意到这个停留的性质近乎无用,因为我们可以停留无限短的时间,因此实际上就自动少一秒就行了。

由于时间放状态里肯定空间爆炸,因此只能设计 \(dp_i\),表示看 \(i\) 张幻灯片需要的时间,那么很自然想到 \(dp_{i,j}\) 表示到看 \(i\) 个幻灯片,并且当前在 \(j\) 教室使用的最少时间,但是这样子转移非常痛苦,因为我们容易发现,我们不知道旧的幻灯片有没有被看过。

因此设计 \(dp_{i,j,k}\) ,其中 \(k\) 表示对面的幻灯片有没有被看过,有的话为1,否则为0

转移可以看代码,还是比较好想的。

具体展开下:

假定当前处理到了 tim = dp_{i,j,k},当前位置为nw,如果当前不属于任何区间,nw=0,下一个位置为 nxt,另一个房间的区间为oth,则有以下转移(扩展):

f[i + (oth && (k ^ 1))][j^1][(nw && (find(j,tim+2*K) == nw))] = min(f[i + (oth && (k ^ 1))][j^1][(nw && (find(j,tim+2*K) == nw))],tim + K);

这个式子的意思是:考虑从到另一个房间,如果对面房间有幻灯片 oth 并且我没有看过 oth,那么就 +1,否则不变。如果当前的 nw 与在 tim+2K 的时刻看到的是一个幻灯片,那么 k=1,否则为 0

f[i+1][j][(k && oth && (find(j^1,a[j][nxt].l + K) == oth))] = min(f[i+1][j][(k && oth && (find(j^1,a[j][nxt].l + K) == oth))],a[j][nxt].l);

这个式子的意思是:考虑留在当前房间,如果在 tim 时刻对面的幻灯片和等到下一个时刻的幻灯片是一个,且当前 k=1,那么就 k=1,否则不变。

所以 DP 的式子是好想的,但是因为细节很多,所以看着是依托。

注意到最多只需要重复一次,因此不需要跑最短路,转移两次就行了。

Code

感觉写了依托……

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 3e5 + 10;
const int inf = 0x3f3f3f3f;
int n[2],K;
struct node{
	int l,r;
	bool operator < (const node &a) const{
		return l < a.l;
	}
	bool operator < (const int x) const{
		return r < x;
	}
}a[2][N];
int f[N << 1][2][2];
int search(int id,int x){
	return lower_bound(a[id] + 1,a[id] + 1 + n[id],x) - a[id];
}
int find(int id,int x){
	int now = search(id,x);
	if(a[id][now].l > x) return 0;
	return now;
}
int suf(int id,int x){
	int now = search(id,x);
	if(a[id][now].l <= x) now ++ ;
	return now;
}
int main()
{
	IOS;
	cin >> n[0] >> n[1] >> K;
	for(int i=1;i<=n[0];i++){
		cin >> a[0][i].l >> a[0][i].r;
		a[0][i].r -- ;
	}
	for(int i=1;i<=n[1];i++){
		cin >> a[1][i].l >> a[1][i].r;
		a[1][i].r -- ;
	}
	n[0] ++ ;
	n[1] ++ ;
	a[0][n[0]] = {inf,inf};
	a[1][n[1]] = {inf,inf};
	sort(a[0] + 1,a[0] + 1 + n[0]);
	sort(a[1] + 1,a[1] + 1 + n[1]);
	memset(f,0x3f,sizeof f);
	f[!a[0][1].l][0][0] = 0;
	int ans = 0;
	for(int i=!(a[0][1].l);i <= n[0] + n[1];i ++ ){
		for(int _=0;_<2;_++)
			for(int j=0;j<2;j++){
				for(int k=0;k<2;k++){
					if(f[i][j][k] >= inf) continue;
					int tim = f[i][j][k];
					int nw = find(j,tim);
					int nxt = suf(j,tim);
					int oth = find(j^1,tim+K);
					f[i + (oth && (k ^ 1))][j^1][(nw && (find(j,tim+2*K) == nw))] = min(f[i + (oth && (k ^ 1))][j^1][(nw && (find(j,tim+2*K) == nw))],tim + K);
					f[i+1][j][(k && oth && (find(j^1,a[j][nxt].l + K) == oth))] = min(f[i+1][j][(k && oth && (find(j^1,a[j][nxt].l + K) == oth))],a[j][nxt].l);
					ans =  i;
				}
			}
	}
	cout  << ans;
	return 0;
}
posted @ 2026-01-09 10:01  WinterXorSnow  阅读(2)  评论(0)    收藏  举报