雅礼国庆集训 day1 T2 折射
题面
算法
转化题意
说白了就是给了你一堆点,让你数这种折线有多少个 (严格向下走,并且横坐标之间的差越来越小)
看着像一种在 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;
}
总结
这说明了有些看似顺序很尴尬的题目,说不定瞎搞搞就能减少一个数量级的复杂度