Jzoj P4228 C___思维+动态规划

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/Gx_Man_VIP/article/details/86683176

题目大意:

平面直角坐标系上有 n n 个整点 ( x i , y i ) (x_i,y_i) ,每个点向上下左右四个方向之一连出一条射线,这些射线不能相交且射线不能经过除了发出点之外的其他点。
有多少种方法选择每个点的方向,使得没有冲突,输出方案数对 998244353 998244353 取模后的值。

n 54 i , j x i x j y i y j x i , y i 10 9 n ≤ 54,对于所有i, j,有x_i ≠ x_j或y_i ≠ y_j,且|x_i|, |y_i| ≤ {10} ^ 9

分析:

一个点的某个方向上有另一点,则这个方向一定无法选择
然后我们考虑 d p dp
n n 个点以 x x 为第一关键字升序排列, x x 相同时将 y y 升序排列
然后令 f o p t , i , j , k , l f_{opt,i,j,k,l} 表示前 o p t opt 个点中选出点的组合使得满足
①发出射线方向向右的点的纵坐标 y y 最大的点为点 i i ,反之, y y 最小的点为 j j
②发出射线方向向上的点的纵坐标 y y 最小的点为点 k k
③发出射线方向向下的点的纵坐标 y y 最大的点为点 l l
的方案数的总和。

初值: f 0 , 0 , 0 , 0 , 0 = 1 f_{0,0,0,0,0}=1
然后我们考虑对于第 o p t opt 个点,
然后枚举射线方向,如果这个方向能够畅通(无其他点阻碍),则
我们枚举 i , j , k , l i,j,k,l ,当 f o p t 1 , i , j , k , l f_{opt-1,i,j,k,l} 不为 0 0 (有方案存在)时,
考虑转移
射线向上, 且 y o p t > y i y_{opt} > y_i ,则它不会与这个组合中的所有线相交,有可能更新 k k
f o p t , i , j , m i n ( k , o p t ) , l + = f o p t 1 , i , j , k , l f_{opt,i,j,min(k,opt),l} += f_{opt-1,i,j,k,l}
射线向下,且 y o p t < y j y_{opt} < y_j ,则它不会与这个组合中的所有线相交,有可能更新 l l
f o p t , i , j , k , m a x ( l , o p t ) + = f o p t 1 , i , j , k , l f_{opt,i,j,k,max(l,opt)}+=f_{opt-1,i,j,k,l}
射线向左,且 y l y o p t y k y_{l}<y_{opt}<y_{k} ,则它不会与这个组合的所有线相交,也没可能比 i , j , k , l i,j,k,l 更优。
f o p t , i , j , k , l + = f o p t 1 , i , j , k , l f_{opt,i,j,k,l}+=f_{opt-1,i,j,k,l}
射线向右,此时不需要有任何限制,也不会和这个组合的所有线相交,可能更新 k , l k,l
f o p t , i , j , k , l + = f o p t 1 , i , j , k , l f_{opt,i,j,k,l}+=f_{opt-1,i,j,k,l}
// m i n ( x , y ) min(x,y) , m a x ( x , y ) max(x,y) 是根据其纵坐标比较,返回的是对应点编号。
时间复杂度: O ( n 5 ) O(n^5)
但是因为有各种情况的剪枝跑不满,
然后就过了,注意滚动数组优化第一维内存

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>

#define N 55

using namespace std;

const int modn = 998244353;

struct Node { int x, y; }a[N];
int dp[2][N][N][N][N], n, total;

bool cmp(Node aa, Node bb)
{
    if (aa.x == bb.x) return aa.y < bb.y;
	return aa.x < bb.x; 
}

int Minid(int x, int y)
{
	if (!x) return y;
	if (!y) return x;
    if (a[x].y < a[y].y) return x;
    return y;
}

int Maxid(int x, int y)
{
    if (!y) return x;
    if (!x) return y;
    if (a[x].y < a[y].y) return y;
    return x;
}

bool check(int p, int q, int opt)
{
    if (opt == 1 && a[p].x == a[q].x && a[p].y < a[q].y) return 1; 
    if (opt == 2 && a[p].x == a[q].x && a[p].y > a[q].y) return 1;
    if (opt == 3 && a[p].y == a[q].y && a[p].x > a[q].x) return 1; 
    if (opt == 4 && a[p].y == a[q].y && a[p].x < a[q].x) return 1; 
    return 0;
}

int main()
{
    int n, ans = 0;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d %d", &a[i].x, &a[i].y);
    sort(a + 1, a + n + 1, cmp);
    dp[0][0][0][0][0] = 1;
    for (int C = 1; C <= n; C++)
    { 
        int noww = C % 2;
        int past = (C + 1) % 2; 
        for (int opt = 1; opt <= 4; opt++)
        {
            bool usepower = 0;
            for (int D = 1; D <= n; D++) 
			{ usepower |= check(C, D, opt); if (usepower) break; }
            if (!usepower)
            {
                for (int i = 0; i < C; i++)
                    for (int j = 0; j < C; j++)
                        for (int k = 0; k < C; k++)
                            for (int l = 0; l < C; l++)
                                if (dp[past][i][j][k][l])
                                {
                                    if (opt == 1 && (a[C].y > a[i].y || !i))
                                       dp[noww][i][j][Minid(C, k)][l] = (dp[noww][i][j][Minid(C, k)][l] + dp[past][i][j][k][l]) % modn;
                                    if (opt == 2 && (a[C].y < a[j].y || !j))
                                       dp[noww][i][j][k][Maxid(C, l)] = (dp[noww][i][j][k][Maxid(C, l)] + dp[past][i][j][k][l]) % modn;
                                    if (opt == 3 && ((a[k].y > a[C].y && a[l].y < a[C].y) || (!k && !l) || 
									                 (a[k].y > a[C].y && !l) || (a[l].y < a[C].y && !k)))
                                       dp[noww][i][j][k][l] = (dp[noww][i][j][k][l] + dp[past][i][j][k][l]) % modn;
                                    if (opt == 4)
                                       dp[noww][Maxid(C, i)][Minid(C, j)][k][l] = (dp[noww][Maxid(C, i)][Minid(C, j)][k][l] + dp[past][i][j][k][l]) % modn;     
                                }   
            }
        }
        for (int i = 0; i <= C; i++)
            for (int j = 0; j <= C; j++)
                for (int k = 0; k <= C; k++)
                    for (int l = 0; l <= C; l++) dp[past][i][j][k][l] = 0;
    }
    
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
            for (int k = 0; k <= n; k++)
                for (int l = 0; l <= n; l++)
                    total = (total + dp[n % 2][i][j][k][l]) % modn;
    printf("%d\n", total);
}

猜你喜欢

转载自blog.csdn.net/Gx_Man_VIP/article/details/86683176