JZOJ 4228. 【五校联考3day2】C
题目
大意
有n个祭坛,每个祭坛有东西南北四个方向
每个祭坛可以选择一个方向发出射线,保证射线不能相交以及射线不能经过其他祭坛
抽象的来说,如果我们以东方向为x轴,北方向为y轴,建立笛卡尔坐标系,那么每个祭坛将会对应一个整点。每个点向上下左右四个方向之一连出一条射线,这些射线不能相交且射线不能经过除了发出点之外的其他点。
求有多少种方法选择每个祭坛的方向,使得祭坛间不发生冲突
分析
-
首先我们肯定先想到暴力了
- 但很显然超时,所以正解是个DP
- 首先f[l][r][u][d][0||1]表示
当做到第i个时,向下的祭坛的y坐标最大点是l,向上的祭坛的y坐标最小的点是r,向右的祭坛的y坐标最小点是u,最大点是d
-
枚举一个最大点但是有很多状态时没有用的
所以达不到O(n^5)卡卡常???
代码
1 #include <cstdio> 2 #include<bits/stdc++.h> 3 #include <iostream> 4 #include <cmath> 5 #include <cstring> 6 #include <algorithm> 7 #define ll long long 8 #define N 55 9 using namespace std; 10 int f[N][N][N][N][2]; 11 inline int read() 12 { 13 int x=0,f=1;char c=getchar(); 14 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 15 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 16 return x*f; 17 } 18 struct sb 19 { 20 int x,y; 21 }a[N]; //up down left right roll 22 bool bz; 23 inline int Max(int x,int y) 24 { 25 if (!y) return x; 26 if (!x) return y; 27 if (a[x].y>a[y].y)return x; 28 else return y; 29 } 30 inline int Min(int x,int y) 31 { 32 if (!y) return x; 33 if (!x) return y; 34 if (a[x].y<a[y].y) return x; 35 else return y; 36 } 37 inline bool cmp(sb a,sb b) 38 { 39 return a.x<b.x || (a.x==b.x && a.y<b.y); 40 } 41 inline bool pd(int i,int j,int k) 42 { 43 if (j==1 && a[k].x==a[i+1].x && a[k].y>a[i+1].y) return false; 44 if (j==2 && a[k].x==a[i+1].x && a[k].y<a[i+1].y) return false; 45 if (j==3 && a[k].y==a[i+1].y && a[k].x<a[i+1].x) return false; 46 if (j==4 && a[k].y==a[i+1].y && a[k].x>a[i+1].x) return false; 47 return true; 48 } 49 int main() 50 { 51 ios::sync_with_stdio(false); 52 int n,ans=0,l,r,u,d,i,j; 53 n=read(); 54 for (int i=1;i<=n;i++) 55 a[i].x=read(),a[i].y=read(); 56 sort(a+1,a+n+1,cmp); 57 int p=0,q=1; 58 f[0][0][0][0][0]=1; 59 for (register int i=0;i<n;i++) 60 { 61 for (register int j=1;j<=4;j++) 62 { 63 bz=true; 64 for (register int k=1;k<=n;k++) 65 if (!pd(i,j,k)) 66 { 67 bz=false; 68 break; 69 } 70 if (bz) 71 { 72 for (register int l=0;l<=i;l++) 73 for (register int r=0;r<=i;r++) 74 for (register int u=0;u<=i;u++) 75 for (register int d=0;d<=i;d++) 76 { 77 if (f[l][r][u][d][p]) 78 { 79 if (j==1 && (a[l].y<a[i+1].y || !l)) 80 f[l][r][Min(i+1,u)][d][q]=(f[l][r][Min(i+1,u)][d][q]+f[l][r][u][d][p])%998244353; 81 if (j==2 && (a[r].y>a[i+1].y || !r)) 82 f[l][r][u][Max(i+1,d)][q]=(f[l][r][u][Max(i+1,d)][q]+f[l][r][u][d][p])%998244353; 83 if (j==3 && ((a[u].y>a[i+1].y && a[d].y<a[i+1].y) || (!u && !d) || (a[u].y>a[i+1].y && !d) || (a[d].y<a[i+1].y && !u))) 84 f[l][r][u][d][q]=(f[l][r][u][d][q]+f[l][r][u][d][p])%998244353; 85 if (j==4) 86 f[Max(i+1,l)][Min(i+1,r)][u][d][q]=(f[Max(i+1,l)][Min(i+1,r)][u][d][q]+f[l][r][u][d][p])%998244353; 87 } 88 } 89 } 90 } 91 p=(p+1)&1; 92 q=(q+1)&1; 93 for(register int l=0;l<=n;l++) 94 for (register int r=0;r<=n;r++) 95 for (register int u=0;u<=n;u++) 96 for (register int d=0;d<=n;d++) 97 f[l][r][u][d][q]=0; 98 } 99 for(register int l=0;l<=n;l++) 100 for (register int r=0;r<=n;r++) 101 for (register int u=0;u<=n;u++) 102 for (register int d=0;d<=n;d++) 103 ans=(ans+f[l][r][u][d][p])%998244353; 104 cout<<ans; 105 return 0; 106 }
为何要逼自己长大,去闯不该闯的荒唐