雅礼国庆集训 day1 T2 折射

题面

题面下载

算法

转化题意

说白了就是给了你一堆点,让你数这种折线有多少个 (严格向下走,并且横坐标之间的差越来越小)
pAGu6Sg.png

看着像一种在 y 轴方向排序的 dp
但是由于是折线, 所以需要加一维来判断转向

dp 设计

状态设计

\(dp_{i, 0/1}\) 表示第 i 个点, 是向左下还是右上

状态转移方程

最初想到从 y 轴, 从上往下递推, 但是这样满足不了抽象的 x 轴约束, 因此考虑从 x 轴方向递推
于是有递推式子

\[dp_{i, 0} = dp_{i, 0} + dp_{j, 1} ( y_j < y_i ) \]

\[dp_{j, 1} = dp_{i, 0} + dp_{j, 1} ( y_j > y_i ) \]

边界条件

\[dp_{i, 0} = 1, dp_{i, 1} = 1 \]

时间复杂度

优秀啊

代码

#include <bits/stdc++.h>
const int MAXN = 1e5 + 20;
const int MOD = 1e9 + 7;
int n, m;

int dp[MAXN][2];

int ans = 0;
struct node
{
    int x, y;

    friend bool operator < (node a, node b)
    {
        return a.x < b.x;
    }
} p[MAXN];

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d %d", &p[i].x, &p[i].y);
    }
        
    std::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[i].y > p[j].y)
            {
                dp[i][0] = (dp[i][0] + dp[j][1]) % MOD;
            }
            else
            {
                dp[j][1] = (dp[i][0] + dp[j][1]) % MOD;
            }
        }
            
    }
    for (int i = 1; i <= n; i++)
    {
        ans = (ans + (dp[i][0] + dp[i][1] - 1) % MOD) % MOD;
    }
        
    printf("%d\n", ans);
    return 0;
}

总结

这说明了有些看似顺序很尴尬的题目,说不定瞎搞搞就能减少一个数量级的复杂度

posted @ 2024-10-07 18:43  Yorg  阅读(5)  评论(0编辑  收藏  举报