Problem 4 dp

$des$

小 $Y$ 十分喜爱光学相关的问题, 一天他正在研究折射.
他在平面上放置了 $n$ 个折射装置, 希望利用这些装置画出美丽的折线.
折线将从某个装置出发, 并且在经过一处装置时可以转向, 若经过的装置坐
标依次为 $(x_1, y_1), (x_2, y_2) ... (x_k, y_k ),$ 则必须满足:
$\bullet \forall j \in (1, k], y_j < y_{j - 1}$
$\bullet \forall j \in (2, k], x_{j - 2} < x_{j} < x_{j - 1} 或者 x_{j - 1} < x_j < x_{j - 2}$
求不同种的画法

$sol$

按 $x$ 坐标排序,$f_{i, 0/1}$ 表示以第 $i$ 个点为顶端下来向左或向右的折线的方案数
从左到右加点,考虑前 $i$ 个点构成的包含 $i$ 点的折线,由于新点横坐标最大, 所以只可能在折线的
第一位或第二位:
1. $\forall y_j < y_i, f_{i, 0} \gets f_{j, 1}$
2. $\forall y_j > y_i, f_{j, 1} \gets f_{k, 0} | x_k > x_j 且 y_k < y_i$
第二种情况可以前缀和优化, 复杂度 $O(n^2)$

$code$

#include <bits/stdc++.h>

using std::pair;

typedef long long ll;
typedef pair<int, int> pii;

#define fst first
#define snd second

const int oo = 0x3f3f3f3f;

#define gc getchar()
inline int read() {
    int x = 0; char c = gc;
    while(c < '0' || c > '9') c = gc;
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
    return x;
}

const int N = 6000;
const int mo = 1e9 + 7;

pii p[N + 5];
int dp[N + 5][2], n;

int main() {
    n = read();
    for(int i = 1; i <= n; i++) p[i].fst = read(), p[i].snd = read();
    sort(p + 1, p + n + 1);
    for(int i = 1; i <= n; i++) {
        dp[i][0] = dp[i][1] = 1;
        for(int j = i - 1; j >= 1; j--)
            if(p[j].snd > p[i].snd) (dp[j][1] += dp[i][0]) %= mo;
            else (dp[i][0] += dp[j][1]) %= mo;
    }
    int ans = mo - n;
    for(int i = 1; i <= n; i++) ans = ((ans + dp[i][0]) % mo + dp[i][1]) % mo;
    std:: cout << ans;
    return 0;
}

 

posted @ 2018-10-10 20:35  xayata  阅读(252)  评论(1编辑  收藏  举报