注:此后不提供题面。
思路:前缀和
严格讲也许是叫后缀和~
C型图案的产生
产生条件
首先,C型图案都需要什么条件才能出现?
- 上层宽度大于 1
- 中间 n 层连续
- 下层宽度大于 1
所以,对这三个条件依次处理。
上层宽度
建立一个前缀和数组 maxw[i][j],表示 (i,j) 向右最多有几格连续的地面(不是坑)。
由于宽度要大于 1,所以当右边相邻的格子为坑时,maxw 也为 0。
1 2 3 4 5 6
| for(int i = n; i >= 1; i--) { for(int j = m - 1; j >= 1; j--) { if(hole[i][j] || hole[i][j + 1]) continue; maxw[i][j] = maxw[i][j + 1] + 1; } }
|
乘法原理
思考:如果上层宽度为 a,下层宽度为 b,那总方案数为 a⋅b。
同时,可以有多个上层和下层拼出C型图案。
所以,如果第 i 层宽度为 x,前面几层(不含相邻,空出来一行)的总宽度为 y,那么这一层能产生的方案数为 x⋅y。
下层宽度
首先,既然要对每一层查找,就应该外层循环宽度,内层循环高度。
接下来,用 lst 保存前面几层的总宽度,那么就需要在本层循环结束后再将上一层的宽度合并到 lst,理由同上。
所以,到 (i,j) 时,C型方案的数量就为:maxw[i][j]⋅lst。
连续层
如果碰到了坑,直接跳过即可,并将 lst 重置为 0。
F型图案的产生
相似的产生条件
不难发现,F型图案就是在C型图案的基础上加上一个向下的部分。
所以如果找到了C型图案,就可以判断是否能生成F型图案。
和C型图案类似,以下是产生F型图案的条件:
- 上层宽度大于 1
- 中间 n 层连续
- 下层宽度大于 1
- 最下面延伸出去
以上三点直接与C型图案合并即可,我们重点关注最后一条。
向下延伸
使用一个前缀和数组 maxh[i][j] 表示向下延伸出去的最大高度。
1 2 3 4 5 6
| for(int i = n; i >= 1; i--) { for(int j = m - 1; j >= 1; j--) { if(hole[i][j]) continue; maxh[i][j] = maxh[i + 1][j] + 1; } }
|
计数
如果找到了能产生C型图案的位置,也要判断能否产生F型图案。
根据上面的结论,F型图案的方案数为:maxw[i][j]⋅lst⋅maxh[i+1][j]。
只需要循环遍历每一个点,将结果相加即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int ccnt = 0, fcnt = 0; for(int j = 1; j <= m; j++) { int lst = 0; for(int i = 1; i <= n; i++) { if(maxw[i][j]) { const int res = lst * maxw[i][j]; ccnt += res; fcnt += 1ll * res * maxh[i + 1][j]; } if(hole[i][j]) lst = 0; else { lst += maxw[i - 1][j]; } } }
|
注意取模!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <bits/stdc++.h> #define set(x, y) memset(x, y, sizeof x)
using namespace std; using ll = long long;
const int inf = 0x7f7f7f7f;
const int N = 1000 + 10; const int MOD = 998244353;
bool hole[N][N];
int maxw[N][N], maxh[N][N];
void init(){ set(hole, 0); set(maxw, 0); set(maxh, 0); }
int main() { #ifndef ONLINE_JUDGE freopen("plant1.in", "r", stdin); freopen("plant.out", "w", stdout); #endif int T, id; cin >> T >> id; int n, m, c, f; while(T-- > 0) { init(); cin >> n >> m >> c >> f; char ch; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { cin >> ch; hole[i][j] = ch == '1'; } } for(int i = n; i >= 1; i--) { for(int j = m - 1; j >= 1; j--) { if(hole[i][j] || hole[i][j + 1]) continue; maxw[i][j] = maxw[i][j + 1] + 1; } for(int j = m - 1; j >= 1; j--) { if(hole[i][j]) continue; maxh[i][j] = maxh[i + 1][j] + 1; } } int ccnt = 0, fcnt = 0; for(int j = 1; j <= m; j++) { int lst = 0; for(int i = 1; i <= n; i++) { if(maxw[i][j]) { const int res = lst * maxw[i][j] % MOD; ccnt += res; fcnt += (1ll * res * maxh[i + 1][j]) % MOD; } if(hole[i][j]) lst = 0; else { lst += maxw[i - 1][j]; }
ccnt %= MOD; fcnt %= MOD; } } cout << c * ccnt << ' ' << f * fcnt << endl; } return 0; }
|