zoukankan      html  css  js  c++  java
  • [bzoj3688] 折线统计

    Description

    二维平面上有n个点(xi, yi),现在这些点中取若干点构成一个集合S,对它们按照x坐标排序,顺次连接,将会构成一些连续上升、下降的折线,设其数量为f(S)。如下图中,1->2,2->3,3->5,5->6(数字为下图中从左到右的点编号),将折线分为了4部分,每部分连续上升、下降。
    img
    现给定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

    题解

    线段树/bit优化dp。

    (f[i][j][0/1])表示考虑了前(i)个点,有(j)段折线,且最后一段是上升/下降的方案数。

    可以得到一个很显然的转移:

    [f[i][k][0]=sum_{j=1}^{i-1} f[j][k][0]*[a[i]>a[j]]+f[j][k-1][1]*[a[i]>a[j]] ]

    [f[i][k][1]=sum_{j=1}^{i-1} f[j][k-1][0]*[a[i]<a[j]]+f[j][k][1]*[a[i]<a[j]] ]

    注意到(k)的范围只有10,可以暴力枚举后两维,然后用一颗权值线段树来维护第一维。

    #include<bits/stdc++.h>
    using namespace std;
    void read(int &x){
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-f;
        for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+ch-'0';x*=f;
    }
    #define write(x) printf("%d
    ",x)
    #define maxn 100005
    const int mod = 100007;
    int f[maxn][11][2],n,K;
    struct point {int x,y;}a[maxn];
    inline int cmp(point x,point y) {return x.x<y.x;}
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    struct segment_tree {
        int sum[maxn<<2];
        void update(int p) {sum[p]=sum[ls]+sum[rs];}
        void modify(int p,int l,int r,int x,int v) {
            if(l==r) return sum[p]=v%mod,void();
            if(x<=mid) modify(ls,l,mid,x,v);
            else modify(rs,mid+1,r,x,v);
            update(p);
        }
        int query(int p,int l,int r,int x,int y) {
            if(!y) return 0;
            if(x<=l&&r<=y) return sum[p];
            int ans=0;
            if(x<=mid) ans=(ans+query(ls,l,mid,x,y))%mod;
            if(y>mid) ans=(ans+query(rs,mid+1,r,x,y))%mod;
            update(p);return ans;
        }
    }T[11][2];
    #define N 100000
    int main() {
        read(n),read(K);;for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y);
        sort(a+1,a+n+1,cmp);
        //for(int i=1;i<=n;i++) printf("%d %d
    ",a[i].x,a[i].y);
        for(int i=1;i<=n;i++) {
            f[i][0][0]=f[i][0][1]=1;
            T[0][0].modify(1,1,N,a[i].y,1),T[0][1].modify(1,1,N,a[i].y,1);
            for(int k=1;k<=K;k++) {
                f[i][k][0]=(T[k][0].query(1,1,N,1,a[i].y-1)+T[k-1][1].query(1,1,N,1,a[i].y-1))%mod;
                f[i][k][1]=(T[k][1].query(1,1,N,a[i].y+1,N)+T[k-1][0].query(1,1,N,a[i].y+1,N))%mod;
                T[k][0].modify(1,1,N,a[i].y,f[i][k][0]),T[k][1].modify(1,1,N,a[i].y,f[i][k][1]);
                //if(i==3) printf("::%d
    ",T[k][1].query(1,1,N,5,5));
                //printf("%d %d
    ",f[i][1][0],f[i][1][1]);
            }
        }int ans=0;
        //for(int i=1;i<=n;i++) printf("%d %d
    ",f[i][1][0],f[i][1][1]);
        for(int i=1;i<=n;i++) ans=(ans+f[i][K][0]+f[i][K][1])%mod;
        write(ans);
        return 0;
    }
    
  • 相关阅读:
    点餐系统的设计与实现注意点与解决办法
    不借助临时变量交换两个数值
    python2.7之乱码问题
    netty-学习笔记
    每天一个linux命令---curl
    每天一个linux命令---useradd
    webservice 学习笔记
    每天一个linux命令---kill
    XML解析
    每天一个linux命令---tar
  • 原文地址:https://www.cnblogs.com/hbyer/p/10053650.html
Copyright © 2011-2022 走看看