[DP]JZOJ 4228 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<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);
}
View Code

猜你喜欢

转载自www.cnblogs.com/mastervan/p/10331722.html