bzoj3939 Cow Hopscotch

175 篇文章 0 订阅
148 篇文章 0 订阅

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.
就像人类喜欢跳格子游戏一样,FJ的奶牛们发明了一种新的跳格子游戏。虽然这种接近一吨的笨拙的动物玩跳格子游戏几乎总是不愉快地结束,但是这并没有阻止奶牛们在每天下午参加跳格子游戏
游戏在一个R*C的网格上进行,每个格子有一个取值在1-k之间的整数标号,奶牛开始在左上角的格子,目的是通过若干次跳跃后到达右下角的格子,当且仅当格子A和格子B满足如下条件时能从格子A跳到格子B:
1.B格子在A格子的严格右方(B的列号严格大于A的列号)
2.B格子在A格子的严格下方(B的行号严格大于A的行号)
3.B格子的标号和A格子的标号不同 请你帮助奶牛计算出从左上角的格子到右下角的格子一共有多少种不同的方案

Input 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. 第一行包含两个整数R
C K 接下来的R行,每行C个整数表示格子的标号

Output Output the number of different ways one can jump from the
top-left square to the bottom-right square, mod 1000000007.
一行,代表有多少种不同的方案,由于答案很大,请输出答案对1000000007取模的结果

考虑暴力dp,

dp[i][j]=x=1i1y=1j1dp[x][y],c[i][j]c[x][y]

发现这个东西是可以对每个颜色和全体颜色维护前缀和优化的,但是 O(rck) 的空间复杂度开不下,因为操作只有 O(rc) 次,可以采用动态开点线段树,这样空间复杂度是 O(rclogc)
具体来说,从上往下扫描,对于每一行从右往左扫描,这样扫描到当前位置时线段树里的信息就是左上的信息。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int mod=1000000007;
int mp[800][800],root[6000010],lson[6000010],rson[6000010],val[6000010],dp[800][800],
r,c,k,tot,rt;
void modi(int &p,int L,int R,int k,int x)
{
    if (!p) p=++tot;
    val[p]=(val[p]+x)%mod;
    if (L==R) return;
    int mid=L+R>>1;
    if (k<=mid) modi(lson[p],L,mid,k,x);
    else modi(rson[p],mid+1,R,k,x);
}
int qry(int p,int L,int R,int l,int r)
{
    if (!p) return 0;
    if (L==l&&R==r) return val[p];
    int mid=L+R>>1;
    if (r<=mid) return qry(lson[p],L,mid,l,r);
    if (l>mid) return qry(rson[p],mid+1,R,l,r);
    return (qry(lson[p],L,mid,l,mid)+qry(rson[p],mid+1,R,mid+1,r))%mod;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d%d",&r,&c,&k);
    for (int i=1;i<=r;i++)
        for (int j=1;j<=c;j++)
            scanf("%d",&mp[i][j]);
    dp[1][1]=1;
    modi(root[mp[1][1]],1,c,1,1);
    modi(rt,1,c,1,1);
    for (int i=2;i<=r;i++)
        for (int j=c;j>=2;j--)
        {
            dp[i][j]=(qry(rt,1,c,1,j-1)-qry(root[mp[i][j]],1,c,1,j-1)+mod)%mod;
            modi(root[mp[i][j]],1,c,j,dp[i][j]);
            modi(rt,1,c,j,dp[i][j]);
        }
    printf("%d\n",dp[r][c]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值