【bzoj3688】折线统计

  • 本文为博主原创,未经许可不得转载

首先写出方程:

$f[i][j][0]=f[k][j][0]+f[k][j-1][1] (y[i]>y[k])$


$f[i][j][1]=f[k][j][1]+f[k][j-1][0] (y[i]<y[k])$


然后我们发现这个东西随便搞个区间求和就行了,我选择树状数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 100010
using namespace std;
struct node{
int x,y;
bool operator <(const node a)const {return x<a.x;}
}a[MAXN];
const int mod=100007;
int n,m,ans,lim,f[MAXN][20][2],tr[20][2][MAXN];
inline int read(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
void add(int x,int j,int k,int v){while(x<=lim)tr[j][k][x]=(tr[j][k][x]+v)%mod,x+=(x&-x);}
int get(int x,int j,int k){int temp(0);while(x)temp=(temp+tr[j][k][x])%mod,x-=(x&-x);return temp;}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); m=read(); lim=100000;
for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;++i){
f[i][0][0]=f[i][0][1]=1;
add(a[i].y,0,0,1); add(a[i].y,0,1,1);
for(int j=1;j<=m;++j){
f[i][j][0]+=get(a[i].y-1,j-1,1)+get(a[i].y-1,j,0);
f[i][j][1]+=get(lim,j-1,0)-get(a[i].y,j-1,0)+get(lim,j,1)-get(a[i].y,j,1);
f[i][j][0]%=mod; f[i][j][1]%=mod; if(f[i][j][1]<0) f[i][j][1]+=mod;
add(a[i].y,j,0,f[i][j][0]); add(a[i].y,j,1,f[i][j][1]);
}
}
for(int i=1;i<=n;++i) ans+=(f[i][m][0]+f[i][m][1])%mod,ans%=mod;
printf("%d\n",ans);
return 0;
}
文章目录
,