专栏文章

abc388f

AT_abc388_f题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqjeate
此快照首次捕获于
2025/12/04 05:46
3 个月前
此快照最后确认于
2025/12/04 05:46
3 个月前
查看原文
有一个 O(nB)O(nB) 的做法,设 dpidp_i 表示 ii 是否可以到达。
然而,注意到只需要关注每一段区间前的 BB 个和后 BB 个位置的 dpdp 状态,其他的都可以用同余最短路找到规律(当然,由于 BB 很小,也可以直接暴力)。所以复杂度降为 O(mB2)O(m B^2)
code:
CPP
const int MAXN=2e4+5;
bool can[MAXN];
ll n,m,a,b,lcm,gcd;
int l[MAXN],r[MAXN];
vector<int>pos;
bool cou(int l,int r){
	if(r<=0||l<=0)return false;
	if(l>r)return false;
	if(r>n)return false;
	int len=r-l;
	if(len%gcd!=0){
		return false;
	}
	if(len>lcm)return true;
	return can[len];
}
bool check(int x){
	for(int i=0;i<pos.size();i++){
		if(cou(pos[i],x)){
			return true;
		}
	}return false;
}
bool check_(int x){
	for(int i=0;i<pos.size();i++){
		if(x-pos[i]>=a&&x-pos[i]<=b){
			return true;
		}
		if(pos[i]==x){
			return true;
		}
	}return false;
}
map<int,bool>mp;
signed main(){
	scanf("%lld%lld%lld%lld",&n,&m,&a,&b);
	for(int i=1;i<=m;i++){
		scanf("%lld%lld",&l[i],&r[i]);
		if(l[i]+b<=r[i]){
			printf("No\n");
			return 0;
		}
		for(int j=l[i];j<=r[i];j++){
			mp[j]=true;
		}
	}	
	lcm=a*b/__gcd(a,b);
	gcd=__gcd(a,b);
	can[0]=true;
	for(int i=1;i<=lcm;i++){
		if(i>=a)can[i]|=can[i-a];
		if(i>=b)can[i]|=can[i-b];
	}pos.push_back(1);
	l[m+1]=n+1;
	for(int i=1;i<=m;i++){
		vector<int>t;
		for(int j=0;j<=b;j++){
			if(!mp[l[i]-j]&&check(l[i]-j)){
				t.push_back(l[i]-j);
			}
		}
		for(int j=0;j<pos.size();j++){
			if(pos[j]>r[i]){
				t.push_back(pos[j]);
			}
		}
		pos.clear();
		for(int j=0;j<t.size();j++)pos.push_back(t[j]);
		t.clear();
		for(int j=0;j<=b;j++){
			if(!mp[r[i]+j]&&check_(r[i]+j)){
				pos.push_back(r[i]+j);
				t.push_back(r[i]+j);
			}
		}
		pos.swap(t);
	}
	if(check(n)){
		printf("Yes");
	}else{
		printf("No");
	}
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...