P3120 [USACO15FEB] Cow Hopscotch G
由于需要考虑颜色的问题,所以可以考虑将总方法减去相同颜色的方案数,以此得到本次的结果。
使用前缀和,得到此处的方案总数。
然后就需要考虑如何处理颜色的问题了,由于需要进行区间修改与查询,很容易想到使用线段树进行优化,但是按照颜色数写很多树状数组明显空间开不下。
所以使用动态开点的方法。由于一棵树上有只有几个点会被查询,所以我们通过动态开点,只处理需要处理的节点,记录下它的左右儿子即可。
动态开点在需要修改时,开一个新的点记录,查询时直接返回初始状态即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int r,c,k,a[1000][1000],pre[1000],dp[1000][1000];
const int mod=1e9+7;
struct ST{
int c[7000000],ls[7000000],rs[7000000],cnt;
void build(int k){
cnt=k;
}
void pushup(int p){
c[p]=(c[ls[p]]+c[rs[p]])%mod;
}
int New(){
c[++cnt]=0;
ls[cnt]=rs[cnt]=0;
return cnt;
}
void change(int &p,int l,int r,int w,int v){
if(!p)p=New();
if(l==r)return void(c[p]=(c[p]+v)%mod);
int mid=l+r>>1;
if(w<=mid)change(ls[p],l,mid,w,v);
else change(rs[p],mid+1,r,w,v);
pushup(p);
}
int query(int p,int l,int r,int L,int R){
if(!p)return 0;
if(l>=L&&r<=R)return c[p];
int mid=l+r>>1;
int res=0;
if(mid>=L)res+=query(ls[p],l,mid,L,R);
if(mid<R)res+=query(rs[p],mid+1,r,L,R);
res%=mod;
return res;
}
}seg;
signed main(){
cin>>r>>c>>k;
seg.build(k);
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++)cin>>a[i][j];
}
for(int i=1;i<=c;i++)pre[i]=1;
dp[1][1]=1;
seg.change(a[1][1],1,c,1,1);
for(int i=2;i<=r;i++){
for(int j=2;j<=c;j++){
dp[i][j]=(pre[j-1]-seg.query(a[i][j],1,c,1,j-1)+mod)%mod;
}
int tmp=0;
for(int j=2;j<=c;j++){
tmp=(tmp+dp[i][j])%mod;
pre[j]=(pre[j]+tmp)%mod;
seg.change(a[i][j],1,c,j,dp[i][j]);
}
}
cout<<dp[r][c];
return 0;
}

浙公网安备 33010602011771号