BZOJ 3939 [Usaco2015 Feb]Cow Hopscotch ——线段树 CDQ分治
显然dp[i][j]=ps[i-1][j-1]-sigma(dp[k<i][l<j],a[i][j]=a[k][l])
考虑对于每一种颜色都开一颗区间线段树,但是空间不够。
所以我们可以动态开节点的权值线段树即可。
因为ij写反了调了30min。
然后发现空间的问题我们可以分治啊,按照纵坐标分治,然后处理左半边对右半边的影响即可。
然后CDQ分治即可,空间是O(nm)的,时间复杂度是O(nmlogm)的。
复杂度怎么算?主定理套用即可。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define md 1000000007 int sum[6000001],ls[6000001],rs[6000001],tot=0; struct Dynamic_Segment_Tree{ int L,R,rt,X,C; void init(){rt=0;} int query(int x,int l,int r) { if (l>r) return 0; if (!x) return 0; int mid=l+r>>1; if (L<=l&&r<=R) return sum[x]; if (R<=mid) return query(ls[x],l,mid); else if (L>mid) return query(rs[x],mid+1,r); else return (query(ls[x],l,mid)+query(rs[x],mid+1,r))%md; } void update(int x) { sum[x]=(sum[ls[x]]+sum[rs[x]])%md; } void modify(int &x,int l,int r) { if (!x) x=++tot; int mid=l+r>>1; if (l==r) { (sum[x]+=C)%=md; return ; } if (X<=mid) modify(ls[x],l,mid); else modify(rs[x],mid+1,r); update(x); } }T[562501]; int dp[751][751],prs[751][751],r,c,k,a[751][751]; int main() { scanf("%d%d%d",&r,&c,&k); F(i,1,r) F(j,1,c) scanf("%d",&a[i][j]); F(i,1,k) T[i].init(); dp[1][1]=1; F(i,1,r) { F(j,1,c) { (dp[i][j]+=prs[i-1][j-1])%=md; T[a[i][j]].L=1;T[a[i][j]].R=j-1; if (j>=2) (dp[i][j]=dp[i][j]-T[a[i][j]].query(T[a[i][j]].rt,1,c)+md)%=md; prs[i][j]=(((prs[i][j-1]+prs[i-1][j])%md+dp[i][j])%md-prs[i-1][j-1]+md)%md; } F(j,1,c) { T[a[i][j]].X=j;T[a[i][j]].C=dp[i][j]; T[a[i][j]].modify(T[a[i][j]].rt,1,c); } } printf("%d\n",dp[r][c]); }
CDQ分治
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define md 1000000007 int a[751][751],n,m,k,sum[1000005],dp[751][751],ps[751]; void CDQ(int l,int r) { if (l==r) return; int mid=l+r>>1; CDQ(l,mid); F(i,1,n-1) { F(j,l,mid) { (sum[a[i][j]]+=dp[i][j])%=md; (ps[i]+=dp[i][j])%=md; } (ps[i]+=ps[i-1])%=md; F(j,mid+1,r) { (dp[i+1][j]+=ps[i])%=md; dp[i+1][j]=(dp[i+1][j]-sum[a[i+1][j]]+md)%md; } } F(i,1,n) { ps[i]=0; F(j,l,mid) sum[a[i][j]]=0; } CDQ(mid+1,r); } int main() { scanf("%d%d%d",&n,&m,&k); F(i,1,n) F(j,1,m) scanf("%d",&a[i][j]); dp[1][1]=1; CDQ(1,n); printf("%d\n",dp[n][m]); }