问题描述
一个平面直角坐标系上,有N个点,标号为1到N,其中第i个点的坐标为(x[i], y[i])。
求满足以下两个条件的点列{p[i]}的数目(假设{p[i]}的长度为M):
1) 对任意1 <= i < j <= M,必有y[p[i]] > y[p[j]];
2) 对任意3 <= i <= M,必有x[p[i-1]] < x[p[i]] < x[p[i-2]]或者x[p[i-2]] < x[p[i]] < x[p[i-1]]。
求满足条件的非空序列{p[i]}的数目,结果对一个整数Q取模。
对于100%的数据,保证对任何的i,x[i]和y[i]都是1到2000000000之间的整数。
对于100%的数据,保证有当i != j时,有x[i] != x[j]且y[i] != y[j]。
这题很久以前就做了,当时觉得很简单,现在发现它的思路还是有一点借鉴价值.
首先把点按照x坐标排序(不是y坐标)
设dp[i][j][0/1]代表只考虑前i个点,以第j个点为起点,下一个点在它的左边/右边的方案数.
当i增加1时, 从右到左 对每个之前的点考虑第i个点造成的贡献.
当这个点在第i个点以上时,第i个点可以更新这个点的dp值;
当这个点在第i个点以下时,这个点可以更新第i个点的dp值.
显然是可以滚动数组的.
复杂度O(n*n)
说来当时我想了一天,试图优化成O(nlogn) 的复杂度,没想到7000的数据平方可以过......还是清橙上最快的......
所有点的横纵坐标都不相等,所以细节很少
具体做法见代码:
求满足以下两个条件的点列{p[i]}的数目(假设{p[i]}的长度为M):
1) 对任意1 <= i < j <= M,必有y[p[i]] > y[p[j]];
2) 对任意3 <= i <= M,必有x[p[i-1]] < x[p[i]] < x[p[i-2]]或者x[p[i-2]] < x[p[i]] < x[p[i-1]]。
求满足条件的非空序列{p[i]}的数目,结果对一个整数Q取模。
数据规模和约定
对于25%的数据,N <= 50;对于40%的数据,N <= 700;对于60%的数据,N <= 2000;对于70%的数据,N <= 4000;对于100%的数据,1 <= N <= 7000。
对于100%的数据,保证对任何的i,x[i]和y[i]都是1到2000000000之间的整数。
对于100%的数据,保证有当i != j时,有x[i] != x[j]且y[i] != y[j]。
这题很久以前就做了,当时觉得很简单,现在发现它的思路还是有一点借鉴价值.
首先把点按照x坐标排序(不是y坐标)
设dp[i][j][0/1]代表只考虑前i个点,以第j个点为起点,下一个点在它的左边/右边的方案数.
当i增加1时, 从右到左 对每个之前的点考虑第i个点造成的贡献.
当这个点在第i个点以上时,第i个点可以更新这个点的dp值;
当这个点在第i个点以下时,这个点可以更新第i个点的dp值.
显然是可以滚动数组的.
复杂度O(n*n)
说来当时我想了一天,试图优化成O(nlogn) 的复杂度,没想到7000的数据平方可以过......还是清橙上最快的......
所有点的横纵坐标都不相等,所以细节很少
具体做法见代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int x,y;
}pot[7010];
bool cmpx(node A,node B)
{
return A.x<B.x;
}
int n,md;
int dp[7010][2];
int main(){
scanf("%d%d",&n,&md);
for(int i=1;i<=n;i++)
scanf("%d%d",&pot[i].x,&pot[i].y);
sort(pot+1,pot+n+1,cmpx);
for(int i=1;i<=n;i++)
{
dp[i][0]=dp[i][1]=1;
for(int j=i-1;j>=1;j--)
{
if(pot[j].y<pot[i].y)
{
dp[i][0]+=dp[j][1];
if(dp[i][0]>=md) dp[i][0]-=md;
}
else
{
dp[j][1]+=dp[i][0];
if(dp[j][1]>=md) dp[j][1]-=md;
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
ans+=dp[i][0];
if(ans>=md) ans-=md;
ans+=dp[i][1];
if(ans>=md) ans-=md;
}
ans-=n;
if(ans<0) ans+=md;
printf("%d\n",ans);
return 0;
}