Description
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.
Input
Output
Sample Input
1 1 1 1
1 3 2 1
1 2 4 1
1 1 1 1
Sample Output
分析:
一眼dp
设
f[i][j]
f
[
i
]
[
j
]
表示到
(i,j)
(
i
,
j
)
的方案数
f[i][j]=∑f[k][l],k<i且l<j且color[i][j]!=color[k][l]
f
[
i
]
[
j
]
=
∑
f
[
k
]
[
l
]
,
k
<
i
且
l
<
j
且
c
o
l
o
r
[
i
]
[
j
]
!
=
c
o
l
o
r
[
k
]
[
l
]
发现是一个前缀和的形式
对于每一种颜色,建立一棵线段树(记录这种颜色的
f
f
值之和)
而这个线段树的大小只有一行就够了
因为我们在转移的时候是从上到下的,所以我们可以直接把一行一行的信息统计在一起(前缀和的形式啊)
在转移的时候,为了保证转移来自上一步
第二维的循环要从后到前
(看一下代码就明白了)
因为我们给所有的颜色都开一个线段树
为了节省空间,我们用建立主席树的方法动态开点
空间:左右就可以了(均摊)
实际上这道题也可以用CDQ分治
对于纵坐标CDQ分治即可(具体思路其实和线段树一样)
tip
注意取%,很容易炸int哦
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int p=1e9+7;
const int N=755;
int a[N][N],r,c,K,root[N*N],sz=0;
int f[N][N],sum[N][N],sum_line[N];
struct node{
int sum;
int l,r;
};
node t[6001000];
void change(int &rt,int l,int r,int w,int z) {
if (!rt) rt=++sz;
if (l==r) {
t[rt].sum+=z; t[rt].sum%=p;
return;
}
int mid=(l+r)>>1;
if (w<=mid) change(t[rt].l,l,mid,w,z);
else change(t[rt].r,mid+1,r,w,z);
t[rt].sum=(t[t[rt].l].sum%p+t[t[rt].r].sum%p)%p;
}
int ask(int bh,int l,int r,int L,int R) {
if (!bh) return 0;
if (l>=L&&r<=R) return t[bh].sum%p;
int mid=(l+r)>>1;
int ans=0;
if (L<=mid) ans=(ans+ask(t[bh].l,l,mid,L,R)%p)%p;
if (R>mid) ans=(ans+ask(t[bh].r,mid+1,r,L,R)%p)%p;
return ans%p;
}
int main()
{
scanf("%d%d%d",&r,&c,&K);
for (int i=1;i<=r;i++)
for (int j=1;j<=c;j++)
scanf("%d",&a[i][j]);
for (int i=1;i<=c;i++) sum[1][i]=1;
for (int i=1;i<=r;i++) sum[i][1]=1;
f[1][1]=1;
change(root[a[1][1]],1,c,1,1);
for (int i=2;i<=r;i++) {
for (int j=c;j>=1;j--) {
f[i][j]=((sum[i-1][j-1]%p-ask(root[a[i][j]],1,c,1,j-1)%p)%p+p)%p;
change(root[a[i][j]],1,c,j,f[i][j]);
}
for (int j=1;j<=c;j++)
sum[i][j]=(((f[i][j]+sum[i-1][j])%p+sum[i][j-1])%p-sum[i-1][j-1]+p)%p;
}
printf("%d\n",f[r][c]);
return 0;
}