有N行M列的正方形盒子。每个盒子有三种状态0, -1, +1。球从盒子上边或左边进入盒子,从下边或右边离开盒子。规则:
如果盒子的模式是-1,则进入它的球从下面出去。(方向变为向下)
如果盒子的模式是+1,则进入它的球从右面出去。 (反向变为向右)
如果盒子的模式是0, 则进入它的球方向不变。从上面进入的,从下面出去,从左面进入的,从右面出去。
球离开一个盒子,这个盒子的模式切换为相反数。已知,每个盒子的状态,扔k个球,它们都从左上角那个盒子的上面进入(方向向下),问最终有几个球从右下角的盒子的下边出去。
(可以理解维球一个一个放,等待的时间足够长,不会有两个球同时进入一个盒子的情形)本题由Javaman翻译。
Input
第1行:包括3个数M, N, K中间用空格分隔,M,N 为盒子的宽度和高度,K为球的数量(1 <= M, N <= 1000, 1 <= K <= 10^18)。
第2 - N + 1行:每行M个数(-1, 0 或 1),表示对应的模式。
Output
输出1个数,对应最终有有多少个球从右下角的盒子的下边出去。
Input示例
3 2 4
-1 0 -1
1 0 0
Output示例
1
题解
如果一个点为1,则可以认为经过他的球(sum个),有(sum+1)/2个球往右,sum/2个球往下,DP即可。
代码
#include<bits/stdc++.h>
#define inf 0x7fffffff
#define N 20005
#define M 400005
#define ll long long
using namespace std;
inline ll read()
{
ll x=0LL,f=1LL;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll dp[1005][1005][2],k;
int n,m;
int main()
{
m=read();n=read();k=read();
dp[1][1][0]=k;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int t=read();
ll sum=dp[i][j][1]+dp[i][j][0];
if (t==0) dp[i][j+1][1]+=dp[i][j][1],dp[i+1][j][0]+=dp[i][j][0];
if (t==1) dp[i][j+1][1]+=(sum+1)/2,dp[i+1][j][0]+=sum/2;
if (t==-1) dp[i][j+1][1]+=sum/2,dp[i+1][j][0]+=(sum+1)/2;
}
printf("%lld",dp[n+1][m][0]);
return 0;
}