bzoj3688(DP+BIT)

16 篇文章 0 订阅
6 篇文章 0 订阅

这个题还是挺不错的。。和hdu6357很像但又有不同之处。。不如说这个题更具有一般性。。

很容易想到要设扫到i且有j条折线的方案数,可是在转移的时候就不能处理连续上升(下降)的情况,所以得加一维表示折线是上升还是下降

所以设d[i][j][k],表示以i(x坐标)点为末尾,有j个折线的方案数,其中k==1代表折线末尾上升,k==0代表折线末尾下降

那么

d[i][j][0]=\left\{\begin{matrix} d[v][j][0] \\ d[v][j-1][1] \end{matrix}\right. v<i\&\&y_v>y_i

d[i][j][1]=\left\{\begin{matrix} d[v][j][1] \\ d[v][j-1][0] \end{matrix}\right. v<i\&\&y_v<y_i\\

然后按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

 

[Submit][Status][Discuss]



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值