首页 > 代码库 > 动态规划 BZOJ3688 折线统计

动态规划 BZOJ3688 折线统计

3688: 折线统计

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 234  Solved: 118
[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

 

显然是要先按x坐标排序,这不是废话吗2333……y坐标也可以离散了在做,不过没必要

f[i][j][0]/[1]表示前i个点中,选择j段,最后一段为上升/下降的方案数

f[i][j][0]=∑(f[ii][j][0]+f[ii][j-1][1]) (ii<i且node[i].y<node[ii].y)

另一个同理

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int n,k,ans;
 7 struct data{
 8     int x,y;
 9 }node[100010];
10 int f[100010][15][2],t[100010][15][2];
11 bool cmp(const data&aa,const data&bb){
12     return aa.x<bb.x;
13 }
14 void add(int pos,int kk,int tt,int val){
15     for(int i=pos;i<=100000;i+=i&(-i)) t[i][kk][tt]=(t[i][kk][tt]+val)%100007;
16 }
17 int ask(int pos,int kk,int tt){
18     int rt=0;
19     for(int i=pos;i;i-=i&(-i)) rt=(rt+t[i][kk][tt])%100007;
20     return rt;
21 }
22 int main(){
23     scanf("%d%d",&n,&k);
24     for(int i=1;i<=n;i++) scanf("%d%d",&node[i].x,&node[i].y);
25     sort(node+1,node+n+1,cmp);
26     for(int i=1;i<=n;i++){
27         f[i][0][0]=f[i][0][1]=1;
28         add(node[i].y,0,0,1);
29         add(node[i].y,0,1,1);
30         for(int kk=1;kk<=k;kk++){
31             f[i][kk][0]=(f[i][kk][0]+ask(node[i].y-1,kk,0)+ask(node[i].y-1,kk-1,1))%100007;
32             f[i][kk][1]=(f[i][kk][1]+ask(100000,kk,1)-ask(node[i].y,kk,1)+ask(100000,kk-1,0)-ask(node[i].y,kk-1,0))%100007;
33             if(f[i][kk][1]<0) f[i][kk][1]+=100007;//!!!
34             add(node[i].y,kk,0,f[i][kk][0]);
35             add(node[i].y,kk,1,f[i][kk][1]);
36         }
37     }
38     for(int i=1;i<=n;i++){
39         ans=(ans+f[i][k][0])%100007;
40         ans=(ans+f[i][k][1])%100007;
41     }
42     printf("%d\n",ans);
43     return 0;
44 }

 

动态规划 BZOJ3688 折线统计