1 条题解
-
0
首先,可以发现最终两种作物的生长范围一定能够被一条从左上到右下的每次只能向下或向右的线分割:

可以注意到,在内拐角处是必须安装对应洒水器的:

而其它空格则可以选择是否要安装当前所处位置对应的洒水器:

因此,如果中间的这条线确定了,不难求出其对应的方案数。
接着,给方格和格点这样进行编号:

最左上角的格点是 ,与一个格点坐标表示相同的方格在这个格点的左上角。
考虑 dp。设 表示中间这条线走到了格点 (
好像跳舞的线),且最后一次走的方向是向右/下时,考虑 及其左上角所有方格,总共可能的方案数。那么就可以这么转移:
首先考虑 。它的上一步可以是向下的,也可以是向右的。
如果是向右的:

计算方案的范围从 的左上角变成了 的左上角,多了在第 列前 行安 A 型洒水器的方案数。设从方格 到方格 的范围内共有 个格子是空的,那么这样的方案数就是 。 可以前缀和算出。
如果是向下的:

计算方案的范围同样是从 的左上角变成了 的左上角,多了在第 列前 行安 A 型洒水器的方案数。那么这个和上一种情况有什么区别呢?区别在于这种情况会产生一个拐角,而拐角内侧的格子必须放一个 A 型洒水器。因此,如果内侧的格子 被 W 占据,则这种情况的方案数应为 ;如果没有,方案数也应该是 (而不是 )。
最终 应该是上面两种情况的方案数之和。
同理:

在这种情况下,方案数为 ,其中 是 左侧空格的数量。

在这种情况下,若 不是空地,则方案数为 ;否则为 。
即为上面两种情况的方案数之和。
最后输出 即可。
记得随时取模。
#include<bits/stdc++.h> using namespace std; const int N=2147,mod=1e9+7; bool a[N][N]; #define int long long int sl[N][N],su[N][N]; int dp[N][N][2]; int ksm(int a,int b){ if(b<0)return 0; int s=1; while(b){ if(b&1)(s*=a)%=mod; (a*=a)%=mod; b>>=1; } return s; } signed main(){ ios::sync_with_stdio(0);cin.tie(0); int n;cin>>n; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){ char c;cin>>c; a[i][j]=(c=='W'); sl[i][j]=sl[i][j-1]+1-a[i][j]; su[i][j]=su[i-1][j]+1-a[i][j]; } for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++){ if(i*j==0){ if(i==0)dp[i][j][0]=1; if(j==0)dp[i][j][1]=1; continue; } dp[i][j][0]=(dp[i][j-1][0]*ksm(2,su[i][j])%mod+(a[i][j]==0)*dp[i][j-1][1]*ksm(2,su[i][j]-1)%mod)%mod; dp[i][j][1]=(dp[i-1][j][1]*ksm(2,sl[i][j])%mod+(a[i][j]==0)*dp[i-1][j][0]*ksm(2,sl[i][j]-1)%mod)%mod; //cout<<dp[i][j][0]<<"|"<<dp[i][j][1]<<" "; }//cout<<endl; } cout<<(dp[n][n][0]+dp[n][n][1])%mod; return 0; }BTW 上面代码由于底数是固定的所以其实可以把快速幂改成预处理来着,不过快速幂多一个 也能过这题。
- 1
信息
- ID
- 7084
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 24
- 已通过
- 10
- 上传者