AT_arc157_c ARC157C YY Square
原题链接:ARC157C YY Square
分析
感觉昨天晚上睡觉之前想的也不是很对啊......就是,我们只需要统计有多少条路径上有 i i i 个 Y,以及 Y 的段数就行了。但是,这个复杂度......我不敢恭维啊......所以,还是没有切。
所以,还是要记录具体到了什么位置。
那么,我们分两次计算,由于 ( a + b ) 2 = a 2 + 2 a b + b 2 (a+b)^2=a^2+2ab+b^2 (a+b)2=a2+2ab+b2,所以,我们分两次计算 a 2 a^2 a2 和 2 a b 2ab 2ab。
所以,我们设 d p i , j , k dp_{i,j,k} dpi,j,k 表示在位于 ( x , y ) (x,y) (x,y) 时,我们要求的是 k k k 次方的方案数。
转移有:
- c i , j = c_{i,j}= ci,j=
X, d p i , j , 1 = d p i − 1 , j , 1 + d p i , j − 1 , 1 , d p i , j , 2 = d p i − 1 , j , 2 + d p i , j − 1 , 2 dp_{i,j,1}=dp_{i-1,j,1}+dp_{i,j-1,1},dp_{i,j,2}=dp_{i-1,j,2}+dp_{i,j-1,2} dpi,j,1=dpi−1,j,1+dpi,j−1,1,dpi,j,2=dpi−1,j,2+dpi,j−1,2 - c i , j = c_{i,j}= ci,j=
Y, d p i , j , 2 = d p i − 1 , j , 1 + c i − 1 , j = Y × C i + j − 3 i − 2 + d p i , j − 1 , 1 + c i , j − 1 = Y × C i + j − 3 i − 1 , d p i , j , 2 = d p i − 1 , j , 1 + c i − 1 , j = Y × ( C i + j − 3 i − 2 + 2 × d p i − 1 , j , 1 ) + d p i , j − 1 , 1 + c i , j − 1 = Y × ( C i + j − 3 i − 1 + 2 × d p i , j − 1 , 1 ) dp_{i,j,2}=dp_{i-1,j,1}+c_{i-1,j}=Y\times C_{i+j-3}^{i-2}+dp_{i,j-1,1}+c_{i,j-1}=Y\times C_{i+j-3}^{i-1},dp_{i,j,2}=dp_{i-1,j,1}+c_{i-1,j}=Y\times (C_{i+j-3}^{i-2}+2\times dp_{i-1,j,1})+dp_{i,j-1,1}+c_{i,j-1}=Y\times (C_{i+j-3}^{i-1}+2\times dp_{i,j-1,1}) dpi,j,2=dpi−1,j,1+ci−1,j=Y×Ci+j−3i−2+dpi,j−1,1+ci,j−1=Y×Ci+j−3i−1,dpi,j,2=dpi−1,j,1+ci−1,j=Y×(Ci+j−3i−2+2×dpi−1,j,1)+dpi,j−1,1+ci,j−1=Y×(Ci+j−3i−1+2×dpi,j−1,1)
那个组合数是走到 ( i − 1 , j ) (i-1,j) (i−1,j) 的方案数和走到 ( i , j − 1 ) (i,j-1) (i,j−1) 的方案数。
正解
cpp
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 2005;
int h, w;
int fac[N << 1], inv[N << 1];
string s;
char c[N][N];
int dp[N][N][5];
int qpow(int a, int b){
int res = 1;
while (b){
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int C(int n, int m){
if (n < 0 || m < 0 || n < m)
return 0;
return fac[n] * inv[n - m] % mod * inv[m] % mod;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> h >> w;
fac[0] = 1;
for (int i = 1; i < (N << 1); i++){
fac[i] = fac[i - 1] * i % mod;
}
inv[(N << 1) - 1] = qpow(fac[(N << 1) - 1], mod - 2);
for (int i = (N << 1) - 2; i >= 0; i--){
inv[i] = inv[i + 1] * (i + 1) % mod;
}
for (int i = 1; i <= h; i++){
cin >> s;
for (int j = 1; j <= w; j++){
c[i][j] = s[j - 1];
}
}
for (int i = 1; i <= h; i++){
for (int j = 1; j <= w; j++){
if (c[i][j] == 'X'){
dp[i][j][1] = (dp[i - 1][j][1] + dp[i][j - 1][1]) % mod;
dp[i][j][2] = (dp[i - 1][j][2] + dp[i][j - 1][2]) % mod;
}
else{
dp[i][j][1] = (dp[i - 1][j][1] + (c[i - 1][j] == 'Y') * C(i + j - 3, i - 2) + dp[i][j - 1][1] + (c[i][j - 1] == 'Y') * C(i + j - 3, i - 1)) % mod;
dp[i][j][2] = (dp[i - 1][j][2] + (c[i - 1][j] == 'Y') * (C(i + j - 3, i - 2) + 2 * dp[i - 1][j][1]) % mod + dp[i][j - 1][2] + (c[i][j - 1] == 'Y') * (C(i + j - 3, i - 1) + 2 * dp[i][j - 1][1]) % mod) % mod;
}
}
}
cout << dp[h][w][2];
}
AT_arc157_d ARC157D YY Garden
原题链接:ARC157D YY Garden
分析
这么暴力???
就是说,我们假设竖着切了 p p p 条线,横着切了 q q q 条线,然后,我们必须要求每一行 Y 的数量都是 2 p 2p 2p 的倍数,每一列 Y 的数量都是 2 q 2q 2q 的倍数。然后,拿前缀和直接统计一下就做完了......这个 check 的次数不会很多......
正解
cpp
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 2005;
int h, w;
char c[N][N];
int sh[N], sw[N];
int sum[N][N];
int p[N], q[N];
int cnth[N], cntw[N];
int tot;
int ans;
void check(int kh){
int kw = tot * 2 / kh;
int ch = 0, cw = 0;
for (int i = 1; i <= h; i++){
if (sh[i] != sh[i - 1] && sh[i] % kh == 0){
p[++ch] = i;
}
}
for (int j = 1; j <= w; j++){
if (sw[j] != sw[j - 1] && sw[j] % kw == 0){
q[++cw] = j;
}
}
if (ch * 2 != kw || cw * 2 != kh)
return ;
for (int i = 1; i <= ch; i++){
for (int j = 1; j <= cw; j++){
int tmp = sum[p[i]][q[j]] - sum[p[i - 1]][q[j]] - sum[p[i]][q[j - 1]] + sum[p[i - 1]][q[j - 1]];
if (tmp != 2)
return ;
}
}
memset(cnth, 0, sizeof(cnth));
memset(cntw, 0, sizeof(cntw));
for (int i = 1; i <= h; i++){
if (sh[i] % kh == 0){
cnth[sh[i] / kh]++;
}
}
for (int j = 1; j <= w; j++){
if (sw[j] % kw == 0){
cntw[sw[j] / kw]++;
}
}
int res = 1;
for (int i = 1; i < ch; i++){
res = res * cnth[i] % mod;
}
for (int j = 1; j < cw; j++){
res = res * cntw[j] % mod;
}
ans = (ans + res) % mod;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> h >> w;
string s;
for (int i = 1; i <= h; i++){
cin >> s;
for (int j = 1; j <= w; j++){
c[i][j] = s[j - 1];
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
if (c[i][j] == 'Y'){
sh[i]++;
sw[j]++;
sum[i][j]++;
}
}
}
for (int i = 1; i <= h; i++){
sh[i] += sh[i - 1];
}
for (int j = 1; j <= w; j++){
sw[j] += sw[j - 1];
}
tot = sh[h];
if (tot % 2 == 1){
cout << 0;
return 0;
}
for (int i = 2; i <= h * w; i += 2){
if (tot % i == 0){
check(i);
}
}
cout << ans;
}