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

 

posted @ 2017-06-25 19:28  Galaxies  阅读(355)  评论(0编辑  收藏  举报