BZOJ3939: [Usaco2015 Feb]Cow Hopscotch

来源:互联网 发布:php老虎机源码 编辑:程序博客网 时间:2024/06/06 10:18

题目大意:给定一个棋盘,从左上角走到左下角,每次必须严格向右下走一步并且两个各自的标号不能相同,问一共有多少种走法


设F[i][j]表示走到(i,j)这个格子的方案数,那么转移方程就是严格左上的所有格子的F值和减去和他相同颜色的F值和,前者可以直接维护前缀和得出,后者可以对每种颜色建一个动态开点的线段树来维护,时间复杂度O(NMlognm),空间复杂度O(NMlognm)


#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 751#define M 6000010int mod=1e9+7;using namespace std;int f[N][N],a[N][N],pre[N][N];int rt[N*N],ch[M][2],sum[M],cnt;void addnew(int &y,int l,int r,int v,int w){    if(!y) cnt++,y=cnt;    sum[y]=(sum[y]+w)%mod;    if(l==r) return;    int mid=(l+r)>>1;    if(v<=mid) addnew(ch[y][0],l,mid,v,w);    else addnew(ch[y][1],mid+1,r,v,w);}int check(int x,int l,int r,int ll,int rr){    if(l==ll&&r==rr) return sum[x];    int mid=(l+r)>>1;    if(rr<=mid) return check(ch[x][0],l,mid,ll,rr);    else if(ll>mid) return check(ch[x][1],mid+1,r,ll,rr);    else return (check(ch[x][0],l,mid,ll,mid)+check(ch[x][1],mid+1,r,mid+1,rr))%mod;}int main(){    int r,c,k;    scanf("%d%d%d",&r,&c,&k);    int i,j;    for(i=1;i<=r;i++)    {        for(j=1;j<=c;j++)        {            scanf("%d",&a[i][j]);            if(i!=1&&j!=1)            f[i][j]=(pre[i-1][j-1]-check(rt[a[i][j]],1,c,1,j-1))%mod;            else if(i==1&&j==1) f[i][j]=1;        }        for(j=1;j<=c;j++)        {            pre[i][j]=(((pre[i][j-1]+pre[i-1][j])%mod-pre[i-1][j-1])%mod+f[i][j])%mod;            addnew(rt[a[i][j]],1,c,j,f[i][j]);        }    }    printf("%d",(f[r][c]+mod)%mod);}

0 0