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;
}
posted @ 2025-12-07 11:59  huhangqi  阅读(2)  评论(0)    收藏  举报