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; }
暴力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; }