BZOJ 3688

3688: 折线统计

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

 FJ2014

 

思路就是三维动归,但是如果每一位都用for枚举的话要O(kn^2),太慢了

所以用树状数组维护一下a[i].y以下的所有f数组的前缀和,起到了降维的作用

注意树状数组每一次都应该要维护到N

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 100000+5
#define K 10+2
#define mod 100007
#define lowbit(x) x&(-x)
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s>'9' || s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9' && s>='0'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
struct node{int x,y;}a[N];
bool operator < (node a,node b) {return a.x<b.x;}
int f[12][N][2],n,k;
void add(int k,int x,int opt,int val)
{
    for(int i=x;i<=N;i+=lowbit(i))
        f[k][i][opt]=(f[k][i][opt]+val)%mod;
}
int ask(int k,int x,int opt)
{
    int ans=0;
    for(int i=x;i;i-=lowbit(i))
        ans=(ans+f[k][i][opt])%mod;
    return ans%mod;
}
int main()
{
    n=read();k=read();
    for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
    {
        add(0,a[i].y,0,1),add(0,a[i].y,1,1);
        for(int j=1;j<=k;j++)
        {
            add(j,a[i].y,0, ((ask(j,N,0)-ask(j,a[i].y,0)+ask(j-1,N,1)-ask(j-1,a[i].y,1))%mod+mod)%mod );
            add(j,a[i].y,1, (ask(j-1,a[i].y-1,0)+ask(j,a[i].y-1,1))%mod );
        }
    }
    printf("%d\n",(ask(k,N,0)+ask(k,N,1))%mod);
    return 0;
}

 

posted @ 2018-04-05 23:40 hyf20010101 阅读(...) 评论(...) 编辑 收藏