BZOJ 3939 [Usaco2015 Feb]Cow Hopscotch 线段树

题意: 有一个r*c的图。 每个格子有权值,,从一个格子只能跳到在他的严格右下方权值不同的格子上。 询问从左上角格子跳到右下角格子的方案数。 解析: 考虑暴力递推 我们可以把这个式子转化成严格左上的总和减去同颜色的严格左上的f求和。 所以我们可以对每一个颜色开一个以纵坐标为“线段”的线段树。 这样的话我们每一行倒着枚举即可。 代码:

using namespace std;struct node{int l,r,sum;}seg[M];int col[N][N];int sum[N][N];int f[N][N];int root[N*N];int size;int sum_line[N];void pushup(int rt){seg[rt].sum=(seg[seg[rt].l].sum+seg[seg[rt].r].sum)%mod;}void update(int &rt,int val,int p,int l,int r){if(!rt)rt=++size;if(l==r){seg[rt].sum=(seg[rt].sum+val)%mod;return;}int mid=(l+r)>>1;if(p<=mid)update(seg[rt].l,val,p,l,mid);else update(seg[rt].r,val,p,mid+1,r);pushup(rt);}int query(int rt,int L,int R,int l,int r){int ret=0;if(!rt)return 0;if(L<=l&&r<=R){return seg[rt].sum;}int mid=(l+r)>>1;if(L<=mid)ret=(ret+query(seg[rt].l,L,R,l,mid))%mod;if(R>mid)ret=(ret+query(seg[rt].r,L,R,mid+1,r))%mod;return ret;}int n,m,k;int main(){scanf(“%d%d%d”,&n,&m,&k);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf(“%d”,&col[i][j]);for(int i=1;i<=m;i++)sum[1][i]=1;f[1][1]=1;update(root[col[1][1]],1,1,1,m);for(int i=2;i<=n;i++){for(int j=m;j>=1;j–){int sum1=sum[i-1][j-1];int sum2=query(root[col[i][j]],1,j-1,1,m);f[i][j]=((sum1-sum2)%mod+mod)%mod;update(root[col[i][j]],f[i][j],j,1,m);}for(int j=1;j<=m;j++)sum_line[j]=(sum_line[j-1]+f[i][j])%mod,sum[i][j]=(sum[i-1][j]+sum_line[j])%mod;}printf(“%d\n”,f[n][m]);}

而现在我喜欢深邃的夜空,包容一切的黑暗和隐忍,留下眼泪也没人看见。

BZOJ 3939 [Usaco2015 Feb]Cow Hopscotch 线段树

相关文章:

你感兴趣的文章:

标签云: