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

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3688

    【题解】

    看到K<=10就觉得很py了。

    令f[i,j,0/1]表示到第i个数,选了j段,前面是上升/下降的方案数

    转移就前面的一坨求和就行了。

    然后发现可以在对应的p[i].y的位置插入值,利用树状数组来求和

    就很方便啦,复杂度$O(nKlogn)$

    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    
    const int N = 1e5 + 10, M = 20;
    const int mod = 1e5 + 7;
    
    int n, K;
    struct P {
        int x, y;
        P() {}
        P(int x, int y) : x(x), y(y) {}
        friend bool operator < (P a, P b) {
            return a.x < b.x; 
        } 
    }p[N];
    
    struct BIT {
        int c[N], n;
        # define lb(x) (x & (-x))
        inline void set(int _n) {
            n = _n, memset(c, 0, sizeof c);
        }
        inline void edt(int x, int d) {
            for (; x<=n; x+=lb(x)) {
                c[x] += d;
                if(c[x] >= mod) c[x] -= mod;
            }
        }
        inline int sum(int x) {
            int ret = 0;
            for (; x; x-=lb(x)) {
                ret += c[x];
                if(ret >= mod) ret -= mod;
            }
            return ret;
        }
        inline int sum(int x, int y) {
            if(x > y) return 0;
            int ret = sum(y) - sum(x-1);
            if(ret < 0) ret += mod;
            if(ret >= mod) ret -= mod;
            return ret;
        }
        # undef lb
    }T[M][2];
    
    int f[N][M][2];
    // f[i, j, 0/1] 到了第i个数,选了j个段,上一个是升/降 
    
    int main() {
        cin >> n >> K;
        for (int i=1; i<=n; ++i) scanf("%d%d", &p[i].x, &p[i].y);
        sort(p+1, p+n+1);
        for (int i=0; i<=K; ++i) T[i][0].set(100000), T[i][1].set(100000);
        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=K; ++j) {
                f[i][j][0] += T[j-1][1].sum(1, p[i].y-1) + T[j][0].sum(1, p[i].y-1);
                f[i][j][0] %= mod;
                f[i][j][1] += T[j-1][0].sum(p[i].y+1, 100000) + T[j][1].sum(p[i].y+1, 100000);
                f[i][j][1] %= mod; 
            }
            T[0][0].edt(p[i].y, 1);
            T[0][1].edt(p[i].y, 1);
            for (int j=1; j<=K; ++j) {
                T[j][0].edt(p[i].y, f[i][j][0]);
                T[j][1].edt(p[i].y, f[i][j][1]);
            }
        }
        cout << (T[K][0].sum(1, 100000) + T[K][1].sum(1, 100000)) % mod << endl;
        return 0;
    }
    View Code

    暴力dp:

    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    
    const int N = 1e5 + 10, M = 20;
    const int mod = 1e5 + 7;
    
    int n, K;
    struct P {
        int x, y;
        P() {}
        P(int x, int y) : x(x), y(y) {}
        friend bool operator < (P a, P b) {
            return a.x < b.x; 
        } 
    }p[N];
    
    struct BIT {
        int c[N], n;
        # define lb(x) (x & (-x))
        inline void set(int _n) {
            n = _n, memset(c, 0, sizeof c);
        }
        inline void edt(int x, int d) {
            for (; x<=n; x+=lb(x)) {
                c[x] += d;
                if(c[x] >= mod) c[x] -= mod;
            }
        }
        inline int sum(int x) {
            int ret = 0;
            for (; x; x-=lb(x)) {
                ret += c[x];
                if(ret >= mod) ret -= mod;
            }
            return ret;
        }
        inline int sum(int x, int y) {
            if(x > y) return 0;
            int ret = sum(y) - sum(x-1);
            if(ret < 0) ret += mod;
            if(ret >= mod) ret -= mod;
            return ret;
        }
        # undef lb
    }T[M];
    
    int f[N][M][2];
    // f[i, j, 0/1] 到了第i个数,选了j个段,上一个是升/降 
    
    int main() {
        cin >> n >> K;
        for (int i=1; i<=n; ++i) scanf("%d%d", &p[i].x, &p[i].y);
        sort(p+1, p+n+1);
        for (int i=1; i<=n; ++i) {
            f[i][0][0] = f[i][0][1] = 1;
            for (int j=1; j<=K; ++j) {
                for (int k=1; k<i; ++k) {
                    if(p[k].y < p[i].y) f[i][j][0] += f[k][j-1][1] + f[k][j][0];
                    f[i][j][0] %= mod;
                    if(p[k].y > p[i].y) f[i][j][1] += f[k][j-1][0] + f[k][j][1];
                    f[i][j][1] %= mod; 
                }
            }
        }
        int ans = 0;
        for (int i=1; i<=n; ++i) {
            ans += f[i][K][1] + f[i][K][0];
            ans %= mod;
        }
        cout << ans << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    获取iframe中的元素
    用npm安装express后express命令找不到
    Openfire 单人聊天和多人聊天(发送消息、接收消息)
    openfire拦截数据包与发送广播
    xmpp with openfire 插件-利用Broadcast实现群
    Smack 结合 Openfire服务器,建立IM通信,发送聊天消息
    openfire默认数据库与应用系统数据库整合
    ios即时通讯客户端开发之-mac上安装MySQL
    ios即时通讯客户端开发之-mac上搭建openfire服务器
    IOS block使用中碰到的一个小坑
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3688.html
Copyright © 2011-2022 走看看