传送门
表示有
段,现在以第
个点结尾。
表示最后上升,
表示最后下降。
有转移方程:
用四个树状数组维护这四个和。
先枚举
,然后
枚举完后把树状数组清空,
增加。
和
递推用滚动数组实现。
注意开始时要加上
的贡献。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
const int mod=1e5+7;const int maxn=5e4+10;const int oo=1e5;
int dp[12][maxn][2],tr[oo+10][2][2],n,k,ans=0;
inline void add(int x,int v,int id,int di){for(int i=x;i<=oo;i+=lowbit(i)) tr[i][id][di]=(tr[i][id][di]+v)%mod;}
inline int query(int x,int id,int di,int ret=0){for(int i=x;i>=1;i-=lowbit(i)) ret=ret+tr[i][id][di];return ret%mod;}
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
struct point{
int x,y;
friend inline bool operator<(point a,point b){return a.x<b.x;}
}a[maxn];
int main(){
n=read(),k=read();
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) dp[0][i][0]=dp[0][i][1]=1;
for(int i=1;i<=k;++i){
memset(tr,0,sizeof(tr));
add(a[i].y,dp[i-1][i][0],(i-1)&1,0);
add(a[i].y,dp[i-1][i][1],(i-1)&1,1);
for(int j=i+1;j<=n;++j){
dp[i][j][0]=(query(a[j].y-1,i&1,0)+query(a[j].y-1,(i-1)&1,1))%mod;
dp[i][j][1]=(query(oo,(i-1)&1,0)-query(a[j].y,(i-1)&1,0)+query(oo,i&1,1)-query(a[j].y,i&1,1)+mod)%mod;
add(a[j].y,dp[i][j][0],i&1,0);
add(a[j].y,dp[i-1][j][0],(i-1)&1,0);
add(a[j].y,dp[i][j][1],i&1,1);
add(a[j].y,dp[i-1][j][1],(i-1)&1,1);
}
}
for(int i=1;i<=n;++i) ans=(ans+dp[k][i][0]+dp[k][i][1])%mod;
printf("%d\n",ans);
}