4228. 【五校联考3day2】C

64 篇文章 0 订阅

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。

Solution

dp。

首先如果一个点的某一个方向有另一个点,我们肯定不能往这个方向射射线,因为n很小,所以这个可以n^2预处理出来。

接下来我们按x坐标递增的顺序处理点,发现只需要记录4个东西就可以了:

  • 前i个点中往上射的点的y坐标的最小值。
  • 前i个点中往下射的点的y坐标的最大值。
  • 前i个点中往右射的点的y坐标的最小值。
  • 前i个点中往右射的点的y坐标的最大值。

所以设f[ i ][ J ][ K ][ L ][ S ]表示第前i个点中第J个点往上射的y坐标最小,第K个点往下射的y坐标最大,第L个点往右射的y坐标最小,第S个点往右射的y坐标最大,(休息一下)的方案数。

接下来考虑如何转移。

首先肯定要枚举i,j,k,l,s

      1.  若第i个点往上射。

必须满足第i个点的y坐标大于前面的点中往右射的点的y坐标的最大值。转移时要更新J的值。注意判断没有往右射的点的情况。

      2. 若第i个点往下射。

必须满足第i个点的y坐标小于前面的点中往右射的点的y坐标的最小值。转移时更新K的值。注意判断没有往右射的点的情况。

      3.  若第i个点往左射。

必须满足第i个点的y坐标在前面往上射的点中y坐标的最小值和往下射的点中y坐标的最大值之间。注意判断没有往右射的上界或下界的情况。

      4.  若第i个点往右射。

直接转移。更新L和S。

最后答案即为f[ N ][ 0~N ][ 0~N ][ 0~N ][ 0~N ]的和。但是我们发现这样空间会爆,所以第一维要用滚动。

小优化:若当前f[ i ][ j ][ k ][ l ][ s ]=0则不用转移。会快大概一倍的时间(如果你打的像我一样丑的话)。

Code

#include<cstdio> 
#include<cstring>
#include<algorithm>
#define MOD 998244353
#define N 55
using namespace std;
int n,g[N][5],ans;
long long f[2][N][N][N][N];
//往上min up y
//往下max down y
//往右 min right y
//往右 max right y
struct node{int x,y;}a[N];
bool cmp(node i,node j){return i.x<j.x;}
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;
}
int main(){
    freopen("C.in","r",stdin);
    freopen("C.out","w",stdout);	
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
	scanf("%d%d",&a[i].x,&a[i].y);
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++){
	g[i][1]=g[i][2]=g[i][3]=g[i][4]=1;//up down left right
	for(int j=1;j<=n;j++){
	    if(i!=j){
		if(a[j].x==a[i].x&&a[j].y>a[i].y) g[i][1]=0;
		if(a[j].x==a[i].x&&a[j].y<a[i].y) g[i][2]=0;
		if(a[j].y==a[i].y&&a[j].x<a[i].x) g[i][3]=0;
		if(a[j].y==a[i].y&&a[j].x>a[i].x) g[i][4]=0;
	    }
	}
    }
    if(g[1][1]) f[1][1][0][0][0]=1;
    if(g[1][2]) f[1][0][1][0][0]=1;
    if(g[1][3]) f[1][0][0][0][0]=1;
    if(g[1][4]) f[1][0][0][1][1]=1;
    for(int i=2;i<=n;i++){
        for(int j=0;j<=i-1;j++){
            for(int k=0;k<=i-1;k++){
                for(int l=0;l<=i-1;l++){
                    for(int s=0;s<=i-1;s++){
                        if(a[l].y>a[s].y) continue;
                        f[i&1][j][k][l][s]=0;
                        if(!f[(i-1)&1][j][k][l][s]) continue;
                        if(g[i][1]){ //up
                            if(a[i].y>a[s].y||s==0){
                                f[i&1][Min(i,j)][k][l][s]+=f[(i-1)&1][j][k][l][s]%=MOD;
                            }
                        }
                        if(g[i][2]){ //down
                            if(a[i].y<a[l].y||l==0){
                                f[i&1][j][Max(i,k)][l][s]+=f[(i-1)&1][j][k][l][s]%=MOD;
                            }
                        }
                        if(g[i][3]){ //left
                            if((k==0||k>0&&a[i].y>a[k].y)&&(j==0||j>0&&a[i].y<a[j].y)){
                                f[i&1][j][k][l][s]+=f[(i-1)&1][j][k][l][s]%=MOD;
                            }
                        }
                        if(g[i][4]){ //right
                            f[i&1][j][k][Min(i,l)][Max(i,s)]+=f[(i-1)&1][j][k][l][s]%=MOD;
                        }
                    }
                }
            }
        }
    }
    for(int j=0;j<=n;j++)
        for(int k=0;k<=n;k++)
            for(int l=0;l<=n;l++)
                for(int s=0;s<=n;s++)
                    ans=(ans+f[n&1][j][k][l][s])%MOD;
    printf("%d\n",ans);
    return 0;
}

作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/86682620

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值