给定一个 n 行 m 列的方格,每个格子里有一个正整数 a,1 ≤ a ≤ k,k ≤ n∗m 假设你当前时刻站在 (i,j) 这个格子里,你想要移动到 (x,y),那必须满足以下三个条件 1:i < x 2:j < y 3:第 i 行第 j 列格子里的数不等于第 x 行第 y 列格子里的数 求从 (1,1) 移动到 (n,m) 的不同的方案数
对于 100% 的数据,n,m ≤ 750
容易想到f[i][j]=sigma(f[k][l]|a[k][l]!=a[i][j])
我们可以容易的统计和颜色无关的情况然后去掉颜色相同的就可以了。
于是我们对每一种颜色建立一颗权值线段树
动态开点
时间复杂度O(n^2logn)
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string> #include<string.h> #include<algorithm> #include<math.h> #include<queue> #include<set> #include<map> #include<vector> #define re register #define il inline using namespace std; const int N=1001,NN=8000001; const int mod=1000000007; int n,m,a[N][N],k,root[NN],lch[NN],rch[NN],cnt=0; int f[N][N],s[N][N],w[NN]; il int read(){ re int hs=0;re char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)){ hs=(hs<<3)+(hs<<1)+c-'0'; c=getchar(); } return hs; } il void add(re int &i,re int l,re int r,re int p,re int v){ if(i==0) i=(++cnt); w[i]=(w[i]+v)%mod; if(l==r) return; re int mid=(l+r)/2; if(p<=mid) add(lch[i],l,mid,p,v); else add(rch[i],mid+1,r,p,v); } il int sum(re int i,re int l,re int r,re int p,re int q){ if(!i) return 0; if(l==p&&r==q) return w[i]; re int mid=(l+r)/2; if(q<=mid) return sum(lch[i],l,mid,p,q); if(mid<p) return sum(rch[i],mid+1,r,p,q); return (sum(lch[i],l,mid,p,mid)+sum(rch[i],mid+1,r,mid+1,q))%mod; } int main(){ freopen("hopscotch.in","r",stdin); freopen("hopscotch.out","w",stdout); n=read();m=read();k=read(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) a[i][j]=read(); } f[1][1]=1;add(root[a[1][1]],1,m,1,f[1][1]); for(int i=1;i<=m;i++) s[1][i]=1; for(int i=1;i<=n;i++) s[i][1]=1; for(int i=2;i<=n;i++){ for(int j=2;j<=m;j++){ f[i][j]=(s[i-1][j-1]-sum(root[a[i][j]],1,m,1,j-1)+mod)%mod; s[i][j]=(((s[i-1][j]+s[i][j-1])%mod+f[i][j])%mod-s[i-1][j-1]+mod)%mod; add(root[a[i-1][j]],1,m,j,f[i-1][j]); } } cout<<f[n][m]%mod; return 0; }