[dp] Jzoj P4228 C

Description

在远古的YL国大地上,有n个祭坛,每个祭坛上四个方向写有“艄、毜、鼛、瓯”四个大字,其实这在YL国古代分别是“东、南、西、北”的意思。
YL国每年都要举行祈福消灾的祭祀活动,这个时候,每个祭坛都要在艄毜鼛瓯四个方向中选一个方向,祭坛将向这个方向发出一道隐形的光线,如果两个祭坛发出的光线相交,或者祭坛发出的光线经过了别的祭坛,则祭祀不仅不能成功还将遭到上天的惩罚,如果这些条件都满足则祭祀将成功,YL国在接下来的一年内将不会有任何灾难,甚至只会有人出生不会有人死亡。
抽象的来说,如果我们以“艄”方向为x轴,“瓯”方向为y轴,建立笛卡尔坐标系,那么每个祭坛将会对应一个整点。每个点向上下左右四个方向之一连出一条射线,这些射线不能相交且射线不能经过除了发出点之外的其他点}。
现在他们又到了祭祀活动的时候,他们想知道,有多少种方法选择每个祭坛的方向},使得自己的祭祀能成功?输出方案数对998244353取模后的值}。
 

Input

第一行一个正整数n。
接下来n行,第i + 1行两个整数x_i, y_i,表示第i个祭坛在题目中所述的坐标系下的坐标为(x_i, y_i)。

Output

输出一行一个整数,表示要求的方案数对998244353取模后的值。
 

Sample Input

输入1:
1
1 1
输入2:
2
1 1
2 2
输入3:
6
0 0
0 1
0 2
0 3
0 4
0 5
输入4:
5
1 3
-4 6
2 4
1 6
5 9
输入5:
10
175470546 566770243
501153312 923840801
-36922529 -888266785
-587403745 908979876
-483726071 -96937502
991096990 -783436017
766700568 -679180551
-601529754 815529478
961445805 303768338
245415738 325847411

Sample Output

输出1:
4
样例1解释:只有一个祭坛,显然四个方向都可以发射。
输出2:
14
样例2解释:
对于所有的4 × 4 = 16种情况中,只有两种不可行:
1号祭坛向上,2号向左。
1号向右,2号向下
输出3:
144
样例3解释:
最上面的祭坛可以向左中右三个方向连出射线,最下面的祭坛可以向右下左三个方向连出射线,中间4个祭坛可以向左右连出射线,方案数为3 × 2 × 2 × 2 × 2 × 3 = 144。
输出4:
117
样例4解释:
祭坛的位置如图所示:

输出5:
24341
 

Data Constraint

对于前30%的数据,n ≤ 9。
对于前40%的数据,n ≤ 18。
对于前60%的数据,n ≤ 36。
对于前100%的数据,n ≤ 54,对于所有i, j,有x_i ≠ x_j或y_i ≠ y_j,且|x_i|, |y_i| ≤ {10} ^ 9。

 

题解

  • 这题有那么点恶心。。。
  • 题目大意:在平面直角坐标系上给定n个点,每个点可以从自己出发一条射线,射线不能相互相交,问方案数
  • N<=54,不错不错,可以XJB乱搞一通
  • 先按照x作为第一关键字,y作为第二关键字排序
  • 设f[i][j][k][l][r]为当前做到第i个祭坛,射线向上的祭坛横坐标最小的祭坛为j,射线向下的祭坛横坐标最大的祭坛为k,射线向右的横坐标最小的为l,横坐标最大的为r的方案数
  • 那么考虑一下,如果一个点在另一个点的射程上是不合法的,然后因为一条射线可以无限增长,那么一条向下的射线如果没有左下角向右的射线和右下角向左的射线就是合法的
  • 其他的也是同理,那么如果数组开五维会直接炸掉,可以发现i每次至于i-1有关,是递增的,所以第一位可以滚动
  • 时间复杂度的话,O(N^5)但是会有很多无用的状态,所以是达不到这个时间复杂度的

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N 60
 5 #define mo 998244353 
 6 using namespace std;
 7 struct edge {int x,y;}e[N];
 8 int n,boo,x,y,ans,f[2][N][N][N][N];
 9 bool cmp(edge a,edge b) { return a.x<b.x||a.x==b.x&a.y<b.y; }
10 int min(int x,int y) 
11 { 
12     if (!x) return y; if (!y) return x;
13     return e[x].y<e[y].y?x:y; 
14 }
15 int max(int x,int y) 
16 { 
17     if (!x) return y; if (!y) return x;
18     return e[x].y>e[y].y?x:y; 
19 }
20 bool check(int x,int y,int k)
21 {
22     if (y==1&&e[k].x==e[x].x&&e[k].y>e[x].y) return 0;
23     if (y==2&&e[k].x==e[x].x&&e[k].y<e[x].y) return 0;
24     if (y==3&&e[k].y==e[x].y&&e[k].x<e[x].x) return 0;
25     if (y==4&&e[k].y==e[x].y&&e[k].x>e[x].x) return 0;
26     return 1;
27 }
28 int main()
29 {
30     scanf("%d",&n);
31     for (int i=1;i<=n;i++) scanf("%d%d",&e[i].x,&e[i].y);
32     sort(e+1,e+n+1,cmp),f[0][0][0][0][0]=y=1,x=0;
33     for (int i=1;i<=n;i++)
34     {
35         for (int j=1;j<=4;j++) 
36         {
37             boo=0;
38             for (int k=1;k<=n;k++) if (!check(i,j,k)) { boo=1; break; }
39             if (!boo)
40                 for (int u=0;u<i;u++)
41                     for (int d=0;d<i;d++)
42                         for (int l=0;l<i;l++)    
43                             for (int r=0;r<i;r++)
44                                 if (f[x][u][d][l][r])
45                                 {
46                                     if (j==1&&(e[u].y<e[i].y||!u)) (f[y][u][d][min(i,l)][r]+=f[x][u][d][l][r])%=mo;
47                                     if (j==2&&(e[d].y>e[i].y||!d)) (f[y][u][d][l][max(r,i)]+=f[x][u][d][l][r])%=mo;
48                                     if (j==3&&((e[l].y>e[i].y&&e[r].y<e[i].y)||(!l&&!r)||(e[l].y>e[i].y&&!r)||(e[r].y<e[i].y&&!l))) (f[y][u][d][l][r]+=f[x][u][d][l][r])%=mo;
49                                     if (j==4) (f[y][max(i,u)][min(i,d)][l][r]+=f[x][u][d][l][r])%=mo;
50                                 }
51         }
52         x=x^1,y=y^1,memset(f[y],0,sizeof(f[y]));
53     }
54     for (int u=0;u<=n;u++)
55         for (int d=0;d<=n;d++)
56             for (int l=0;l<=n;l++)
57                 for (int r=0;r<=n;r++)
58                     (ans+=f[x][u][d][l][r])%=mo;
59     printf("%d",ans);
60 }

 

posted @ 2019-01-28 19:52  BEYang_Z  阅读(249)  评论(0编辑  收藏  举报