[DP]JZOJ 4228 C
分析
题面过于沙雕
这题可真是非常奇妙
首先n<55,可以考虑n^4的DP
那么我们考虑要判断是否相交,能否只用四个值表示呢?可以
1、向上射的纵坐标最小的点
2、向下射的纵坐标最大的点
3、向右射的纵坐标最大的点
4、向右射的纵坐标最小的点
左怎么办呢?我们直接排序x,那么只要满足往左射不会碰到点和在1,2中间就可以了
方程分类讨论,有点复杂
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int N=55; const ll P=998244353; struct Point { ll x,y; }a[N]; ll f[2][N][N][N][N]; int n; int MIN(int x,int y) { if (!x) return y;if (!y) return x; if (a[x].y<a[y].y) return x; return y; } int MAX(int x,int y) { if (!x) return y;if (!y) return x; if (a[x].y>a[y].y) return x; return y; } bool CMP(Point a,Point b) { return a.x<b.x||a.x==b.x&&a.y<b.y; } bool Judge(int i,int j,int k) { if (k==0&&a[i].x==a[j].x&&a[i].y<a[j].y) return 0;//up if (k==1&&a[i].x==a[j].x&&a[i].y>a[j].y) return 0;//down if (k==2&&a[i].y==a[j].y&&a[i].x<a[j].x) return 0;//right if (k==3&&a[i].y==a[j].y&&a[i].x>a[j].x) return 0;//left return 1; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y); sort(a+1,a+n+1,CMP); f[0][0][0][0][0]=1; for (int i=0;i<n;i++) { for (int k=0;k<4;k++) { bool Do=1; for (int j=1;j<=n;j++) if (!Judge(i+1,j,k)) { Do=0;break; } if (!Do) continue; for (int l=0;l<=i;l++) for (int r=0;r<=i;r++) for (int u=0;u<=i;u++) for (int d=0;d<=i;d++) if (f[i&1][l][r][u][d]) switch (k) { case 0:{ if (a[l].y<a[i+1].y||!l) (f[(i+1)&1][l][r][MIN(u,i+1)][d]+=f[i&1][l][r][u][d])%=P; break; } case 1:{ if (a[r].y>a[i+1].y||!r) (f[(i+1)&1][l][r][u][MAX(d,i+1)]+=f[i&1][l][r][u][d])%=P; break; } case 2:{ (f[(i+1)&1][MAX(l,i+1)][MIN(r,i+1)][u][d]+=f[i&1][l][r][u][d])%=P; break; } case 3:{ if ((a[u].y>a[i+1].y||!u)&&(a[d].y<a[i+1].y||!d)) (f[(i+1)&1][l][r][u][d]+=f[i&1][l][r][u][d])%=P; break; } default:{ break; } } } for (int l=0;l<=i;l++) for (int r=0;r<=i;r++) for (int u=0;u<=i;u++) for (int d=0;d<=i;d++) f[i&1][l][r][u][d]=0; } ll ans=0; for (int l=0;l<=n;l++) for (int r=0;r<=n;r++) for (int u=0;u<=n;u++) for (int d=0;d<=n;d++) (ans+=f[n&1][l][r][u][d])%=P; printf("%lld\n",ans); }
在日渐沉没的世界里,我发现了你。