动态规划+树状数组优化 BZOJ3688 折线统计
3688: 折线统计
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 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
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 }