Processing math: 100%

#C241101E. ARC184D-Erase Balls 2D


#C241101E. ARC184D-Erase Balls 2D

标签(Label)

  • 动态规划

网址(Website)

[ARC184D] Erase Balls 2D - 洛谷

D - Erase Balls 2D (atcoder.jp)

题目(Problem)

题目描述

在二维平面上有 N 个编号从 1N 的球,第 i 个位于 (Xi,Yi)。其中,X=(X1,X2,,Xn) 以及 Y=(Y1,Y2,,Yn) 分别是一个 1,2,,n 的排列(译注:即横纵坐标分别两两不同)。

你可以执行任意次以下操作:

  • 从剩下的球中选择一个球,记为 k。对剩下的每个球 i,若满足「Xi<XkYi<Yk」或「Xi>XkYi>Yk」(译注:即两球坐标间有二维偏序关系),将其移除。

求操作结束后,可能的剩下球的集合的数量,对 998244353 取模。

输入格式

第一行输入一个数字 N,即球数。

之后 N 行第 i 行输入两个数字 XiYi,即第 i 个球的坐标。

输出格式

输出一个数字,代表取模后的答案。

样例 #1

样例输入 #1

input2
3
1 3
2 1
3 2

样例输出 #1

output1
3

运算后剩余的球的可能集合是 1,2,31,31,2

样例 #2

样例输入 #2

input2
4
4 2
2 1
3 3
1 4

样例输出 #2

output2
3

限制因素

  • 1N300
  • XY(1,2,,N) 的排列。

题解(Solution)

和那道题是一个思维,但是有点区别。

考虑最后会剩下什么,首先不能被删除的点一定会留下,考虑转移。

fi 表示考虑到 y 坐标为 1i 的点的方案数。

如果两个点之前出现了无法删除的点,那么这两个点一定不能直接转移(否则会计算重复),否则一定可以 [i+1,j1] 中间的点都不使用删除操作。

直接 O(n) 暴力求 ij 之间存不存在这些点,再加上枚举 i,j ,总时间复杂度 O(n3)

代码(Code)

c
#include<bits/stdc++.h>
#include<vector>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int> 
#define int long long
#define x first
#define y second
#define inn(x,l,r) (l<=x && x<=r)
inline int rd(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}const int inf = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const int N = 305;
bool ST;
inline void add(int &x,int y){if((x+=y)>=mod)x-=mod;}
inline void sub(int &x,int y){if((x-=y)<0)x+=mod;}

int n,t[N];
P a[N];

bitset<N> can;
int f[N];
void Solve(){
	n=rd();For(i,1,n) a[i]={rd(),rd()}, t[a[i].y] = a[i].x;
	t[0]=n+1, t[n+1]=0;
	
	f[0] = 1;
	For(i,0,n) For(j,0,i){
		if(t[i+1]>t[j]) continue;
		int mxx = -inf, mnx = inf;
		int flag = true;
		For(k,j+1,i) can[k] = false;
		For(k,j+1,i) if(inn(t[k],t[i+1],t[j])){
			if(t[k] < mnx) can[k] = 1;
			mnx = min(mnx, t[k]);
		}
		Rof(k,i,j+1) if(inn(t[k],t[i+1],t[j])){
			if(t[k] > mxx && can[k]) flag = false;
			mxx = max(mxx, t[k]);
		}if(flag) add(f[i+1],f[j]);
	}printf("%lld\n", f[n+1]%mod);
} 

bool ED;
signed main(){
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	int T=1;double Tim=clock();
	while(T--) Solve();
	return cerr<<"TIME:"<<(clock()-Tim)/CLOCKS_PER_SEC,0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !