[CSP-S模拟测试]:折射(DP)
题目描述
小$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}or\ x_{j−1}<x_j<x_{j−2}$
现在他希望你能告诉他,一共有多少种不同的光线能被他画出来,两种光线不同当且仅当经过的折射装置的集合不同。你只需要告诉他答案对${10}^9+7$取模后的结果。
输入格式
第一行一个正整数$n$,表示折射装置的数量。
接下来$n$行,每行两个整数$x_i,y_i$表示折射装置的坐标。
输出格式
输出一行一个整数,表示答案对${10}^9+7$取模后的结果。
样例
样例输入:
4
2 2
3 1
1 4
4 3
样例输出:
14
数据范围与提示
对于$10\%$的数据:$n\leqslant 700,1\leqslant x_i,y_i\leqslant N$
对于$20\%$的数据:$n\leqslant 1,000,1\leqslant x_i,y_i\leqslant N$
对于$50\%$的数据:$n\leqslant 4,000,|x_i|,|y_i|\leqslant {10}^9$
对于$100\%$的数据:$n\leqslant 6,000,|x_i|,|y_i|\leqslant {10}^9$
所有数据满足$\forall i\neq j,x_i\neq x_j\ and\ y_i\neq y_j$。
题解
考试的时候上去就将$y_i$排了个序,然后我就死了……
这道题就是让你找形如下图的图形有多少个:
因为给$y_i$排序不好处理,所以我们考虑给$x_i$排序。
那么我们考虑$DP$,设$dp[i][0/1]$表示第$i$个点为顶端,向左或向右的方案数。
那么我们可以列出状态转移方程:
$\alpha.\forall y_j<y_i,dp[i][0]\leftarrow dp[j][1]$。
$\beta.\forall y_j>y_i,dp[j][1]\leftarrow dp[k][0]|x_k>x_j\ and\ y_k<y_i$。
时间复杂度:$\Theta(n^2)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
int n;
pair<int,int> p[6001];
int dp[2][6001];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&p[i].first,&p[i].second);
sort(p+1,p+n+1);
for(int i=1;i<=n;i++)
{
dp[0][i]=dp[1][i]=1;
for(int j=i-1;j;j--)
p[i].second>p[j].second?dp[0][i]=(dp[0][i]+dp[1][j])%1000000007:dp[1][j]=(dp[1][j]+dp[0][i])%1000000007;
}
for(int i=1;i<=n;i++)dp[0][0]=(dp[0][0]+(dp[0][i]+dp[1][i])%1000000007)%1000000007;
printf("%d",(dp[0][0]-n+1000000007)%1000000007);
return 0;
}
rp++