洛谷P3120 [USACO15FEB]Cow Hopscotch
题目描述
Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a variant of the game for themselves to play. Being played by clumsy animals weighing nearly a ton, Cow Hopscotch almost always ends in disaster, but this has surprisingly not deterred the cows from attempting to play nearly every afternoon.
The game is played on an R by C grid (2 <= R <= 750, 2 <= C <= 750), where each square is labeled with an integer in the range 1..K (1 <= K <= R*C). Cows start in the top-left square and move to the bottom-right square by a sequence of jumps, where a jump is valid if and only if
1) You are jumping to a square labeled with a different integer than your current square,
2) The square that you are jumping to is at least one row below the current square that you are on, and
3) The square that you are jumping to is at least one column to the right of the current square that you are on.
Please help the cows compute the number of different possible sequences of valid jumps that will take them from the top-left square to the bottom-right square.
就像人类喜欢跳格子游戏一样,FJ的奶牛们发明了一种新的跳格子游戏。虽然这种接近一吨的笨拙的动物玩跳格子游戏几乎总是不愉快地结束,但是这并没有阻止奶牛们在每天下午参加跳格子游戏
游戏在一个R*C的网格上进行,每个格子有一个取值在1-k之间的整数标号,奶牛开始在左上角的格子,目的是通过若干次跳跃后到达右下角的格子,当且仅当格子A和格子B满足如下条件时能从格子A跳到格子B:
1.B格子在A格子的严格右方(B的列号严格大于A的列号)
2.B格子在A格子的严格下方(B的行号严格大于A的行号)
3.B格子的标号和A格子的标号不同
请你帮助奶牛计算出从左上角的格子到右下角的格子一共有多少种不同的方案
输入输出格式
输入格式:
The first line contains the integers R, C, and K.
The next R lines will each contain C integers, each in the range 1..K.
输出格式:
Output the number of different ways one can jump from the top-left square to the bottom-right square, mod 1000000007.
输入输出样例
4 4 4 1 1 1 1 1 3 2 1 1 2 4 1 1 1 1 1
5
动规 脑洞题 线段树
很容易想到n^4的暴力DP
可以利用数据结构优化掉两次循环。
记录每个位置左上角的全部方案数(可以用前缀和实现),以及每个颜色在每个位置左上角的全部方案数(可以用动态开点的线段树实现)。
这样每个位置的答案就是左上方总方案数-不合法方案数。少了两层循环
缺少动态开点的意识……思维一直死钻牛角尖,在想用树状数组的话怎么解决空间问题
————————updated 2017.3.21
哇,原来CDQ分治也能做,神奇
%%%隔壁rigel
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mod=1e9+7; 10 const int mxn=500010; 11 int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 int n,m,K,T; 18 int f[751][751]; 19 int s[mxn]; 20 int a[751][751]; 21 int vis[mxn]; 22 void solve(int l,int r){ 23 if(l==r)return; 24 int mid=(l+r)>>1; 25 solve(l,mid); 26 int sum=0; 27 T++; 28 for(int i=2;i<=n;i++){ 29 for(int j=l;j<=mid;j++){ 30 if(vis[a[i-1][j]]!=T){ 31 vis[a[i-1][j]]=T; 32 s[a[i-1][j]]=0; 33 } 34 sum=(sum+f[i-1][j])%mod; 35 (s[a[i-1][j]]+=f[i-1][j])%=mod; 36 } 37 for(int j=mid+1;j<=r;j++){ 38 if(vis[a[i][j]]!=T){ 39 vis[a[i][j]]=T; 40 s[a[i][j]]=0; 41 } 42 f[i][j]=((f[i][j]+sum-s[a[i][j]])%mod+mod)%mod; 43 } 44 } 45 solve(mid+1,r); 46 return; 47 } 48 int main(){ 49 int i,j; 50 n=read();m=read();K=read(); 51 for(i=1;i<=n;i++) 52 for(j=1;j<=m;j++) 53 a[i][j]=read(); 54 f[1][1]=1; 55 solve(1,m); 56 printf("%d\n",f[n][m]); 57 return 0; 58 }
复杂度$O(nmlogn)$
————————
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 #define LL long long 7 using namespace std; 8 const int mod=1e9+7; 9 const int mxn=810; 10 int read(){ 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10-'0'+ch;ch=getchar();} 14 return x*f; 15 } 16 struct node{ 17 int l,r; 18 int sum,mk; 19 }t[(mxn*mxn)<<3]; 20 int rt[mxn*mxn],cnt=0; 21 void update(int p,int v,int l,int r,int &rt){ 22 if(!rt)rt=++cnt; 23 if(l==r){(t[rt].sum+=v)%=mod;return;} 24 int mid=(l+r)>>1; 25 if(p<=mid)update(p,v,l,mid,t[rt].l); 26 else update(p,v,mid+1,r,t[rt].r); 27 t[rt].sum=(t[t[rt].l].sum+t[t[rt].r].sum)%mod; 28 return; 29 } 30 int query(int L,int R,int l,int r,int rt){ 31 if(!rt)return 0; 32 if(L>R)return 0; 33 if(L<=l && r<=R){ 34 return t[rt].sum; 35 } 36 int mid=(l+r)>>1; 37 int res=0; 38 if(L<=mid)res=query(L,R,l,mid,t[rt].l)%mod; 39 if(R>mid)res=(res+query(L,R,mid+1,r,t[rt].r))%mod; 40 return res; 41 } 42 int smm[mxn][mxn]; 43 int f[mxn][mxn]; 44 int a[mxn][mxn]; 45 int n,m,K; 46 void solve(){ 47 int i,j; 48 f[1][1]=1; 49 for(j=1;j<=m;j++)smm[1][j]=1; 50 update(1,1,1,m,rt[a[1][1]]); 51 for(i=2;i<=n;i++){ 52 for(j=1;j<=m;j++){ 53 f[i][j]=(((LL)smm[i-1][j-1]-query(1,j-1,1,n,rt[a[i][j]])%mod)+mod)%mod; 54 } 55 for(j=1;j<=m;j++){ 56 smm[i][j]=(((LL)smm[i-1][j]+smm[i][j-1]-smm[i-1][j-1]+f[i][j])%mod+mod)%mod; 57 update(j,f[i][j],1,m,rt[a[i][j]]); 58 } 59 } 60 printf("%d\n",f[n][m]); 61 return; 62 } 63 int main(){ 64 int i,j; 65 n=read();m=read();K=read(); 66 for(i=1;i<=n;i++) 67 for(j=1;j<=m;j++) 68 a[i][j]=read(); 69 solve(); 70 return 0; 71 }