BZOJ3688. 折线统计(dp+ds)
https://hydro.ac/d/bzoj/p/3688
一个很显然的dp, f ( x , k , 0 / 1 ) f(x,k,0/1) f(x,k,0/1) 表示现在末尾的数为 x x x,已经有 k k k 段线段,之前一直在上/下的方案数,转移显然。
然后前面一维我们遍历 i i i 时只会修改一个 x x x,同时查询其他前后缀的和,那直接树状数组即可。
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
#define mo 100007
#define N 50010
struct node {
int x, y;
}a[N];
int b[N], f0, f1, ans;
int n, m, i, j, k, T, x;
struct Binay_tree {
int cnt[N];
void add(int x, int k) {
while(x < N) (cnt[x] += k) %= mo, x += x & -x;
}
int cha(int x) {
int ans = 0;
while(x) (ans += cnt[x]) %= mo, x -= x & -x;
return ans;
}
int qry(int o, int x) {
if(!o) return cha(x);
return cha(n) - cha(x);
}
}Bin[11][2];
signed main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// srand(time(NULL));
// T=read();
// while(T--) {
//
// }
n = read(); m = read();
for(i = 1; i <= n; ++i) a[i].x = read(), a[i].y = b[i] = read();
sort(a + 1, a + n + 1, [] (node x, node y) { return x.x < y.x; });
sort(b + 1, b + n + 1);
for(i = 1; i <= n; ++i) a[i].y = lower_bound(b + 1, b + n + 1, a[i].y) - b;
for(i = 1; i <= n; ++i) {
x = a[i].y;
// printf("# %d\n", x);
for(k = m; k >= 1; --k) {
f0 = f1 = 0;
f0 = Bin[k][0].qry(0, x);
f1 = Bin[k][1].qry(1, x);
f0 += Bin[k - 1][1].qry(0, x);
f1 += Bin[k - 1][0].qry(1, x);
Bin[k][0].add(x, f0); Bin[k][1].add(x, f1);
}
Bin[0][0].add(x, 1); Bin[0][1].add(x, 1);
}
ans = Bin[m][0].cha(n) + Bin[m][1].cha(n);
printf("%lld", (ans % mo + mo) % mo);
return 0;
}