[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++

posted @ 2019-09-23 21:37  HEOI-动动  阅读(295)  评论(0编辑  收藏  举报