版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qkoqhh/article/details/83189478
这个题还是挺不错的。。和hdu6357很像但又有不同之处。。不如说这个题更具有一般性。。
很容易想到要设扫到i且有j条折线的方案数,可是在转移的时候就不能处理连续上升(下降)的情况,所以得加一维表示折线是上升还是下降
所以设d[i][j][k],表示以i(x坐标)点为末尾,有j个折线的方案数,其中k==1代表折线末尾上升,k==0代表折线末尾下降
那么
然后按j递增枚举,每次按y从小到大维护dp[i][j][1],从大到小维护dp[i][j][0],用BIT就能快速求出满足要求的所有v的状态值
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-12
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid ((x+y)>>1)
#define NM 50005
#define nm 2005
#define pi 3.1415926535897931
const int inf=100007;
using namespace std;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int n,m,b[NM];
int c[NM],ans,d[NM][11][2],_c[NM];
struct P{
int x,y;
bool operator<(const P&o)const{return y<o.y;}
}a[NM];
void add(int x,int t){for(;x<=n;x+=lowbit(x))c[x]+=t,c[x]%=inf;}
int sum(int x,int s=0){for(;x;x-=lowbit(x))s+=c[x],s%=inf;return s;}
void _add(int x,int t){for(;x<=n;x+=lowbit(x))_c[x]+=t,_c[x]%=inf;}
int _sum(int x,int s=0){for(;x;x-=lowbit(x))s+=_c[x],s%=inf;return s;}
int main(){
n=read();m=read();
inc(i,1,n)a[i].x=read(),a[i].y=read(),b[i]=a[i].x;
sort(b+1,b+1+n);
sort(a+1,a+1+n);
inc(i,1,n)a[i].x=lower_bound(b+1,b+1+n,a[i].x)-b;
inc(i,1,n)inc(k,0,1)d[i][0][k]=1;
inc(j,1,m){
mem(c);mem(_c);
inc(k,1,n){int i=a[k].x;
d[i][j][1]=(sum(i)+_sum(i))%inf;
add(i,d[i][j][1]);_add(i,d[i][j-1][0]);
}
mem(c);mem(_c);
dec(k,n,1){int i=a[k].x;
d[i][j][0]=(sum(i)+_sum(i))%inf;
add(i,d[i][j][0]);_add(i,d[i][j-1][1]);
}
}
inc(i,1,n)inc(k,0,1)ans+=d[i][m][k],ans%=inf;
return 0*printf("%d\n",ans);
}
3688: 折线统计
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 374 Solved: 179
[Submit][Status][Discuss]
Description
二维平面上有n个点(xi, yi),现在这些点中取若干点构成一个集合S,对它们按照x坐标排序,顺次连接,将会构成一些连续上升、下降的折线,设其数量为f(S)。如下图中,1->2,2->3,3->5,5->6(数字为下图中从左到右的点编号),将折线分为了4部分,每部分连续上升、下降。
现给定k,求满足f(S) = k的S集合个数。
Input
第一行两个整数n和k,以下n行每行两个数(xi, yi)表示第i个点的坐标。所有点的坐标值都在[1, 100000]内,且不存在两个点,x坐标值相等或y坐标值相等
Output
输出满足要求的方案总数 mod 100007的结果
Sample Input
5 1
5 5
3 2
4 4
2 3
1 1
Sample Output
19
HINT
对于100%的数据,n <= 50000,0 < k <= 10
Source