思路:
首先考慮最暴力的dp,一共是思維數組f[i][j][k][l],表示走到(i,j)時,剛好經過k個0和l個1的路線數,但想都不用想肯定會爆,所以要優化,然后考慮到由於一共經歷了i+j-1個格子,所以有k個0的話,1的個數就是i+j-1-k,此時可以去掉一維,但是此時還是會爆,所以我們通過背包問題的優化思想又可以去掉一維i。
之后狀態方程就可以分類寫成:
1.當a[ i ][ j ] == 0時,dp[ i ][ j ][ k ] = dp[ i - 1 ][ j ][ k - 1 ] + dp[ i ][ j - 1 ][ k - 1 ]
2.當a[ i ][ j ] == 1時,dp[ i ][ j ][ k ] = dp[ i - 1 ][ j ][ k ] + dp[ i ][ j - 1 ][ k ]
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0); using namespace std; typedef long long LL; typedef pair<int, int> PII; const int N = 510, M = 1010, MOD = 998244353; const double PI = acos(-1); int n, m, p, q; int g[N][N]; LL f[N][M]; int main() { IOS; cin >> n >> m >> p >> q; for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) cin >> g[i][j]; //f[i][j][k][l]表示走到(i,j)時,剛好經過k個0和l個1的路線數 //由於一共經歷了i+j-1個格子,所以有k個0的話,1的個數就是i+j-1-k,此時可以去掉一維 //通過背包問題的優化思想又可以去掉一維i if(g[1][1] == 0) f[1][1] = 1;//初始化 else f[1][0] = 1; for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) { if(i == 1 && j == 1) continue; if(g[i][j] == 0) { //注意此時k的枚舉是從后往前來的 for (int k = i + j - 1; k >= 1; k -- ) f[j][k] = (f[j][k - 1] + f[j - 1][k - 1]) % MOD; f[j][0] = 0;// } else { for (int k = i + j - 1; k >= 0; k -- ) f[j][k] = (f[j][k] + f[j - 1][k]) % MOD; } } int res = 0; for (int i = p; i <= n + m - 1 - q; i ++ ) res = (res + f[m][i]) % MOD; cout << res << endl; return 0; }
思路:
由於都采取最優策略,所以可以這么考慮:
每個回合
1:p打f了k滴血,那f可以回k滴血,那p必先疲勞死。
2:p回了k滴血,那f也可以回k滴血,那p照樣先疲勞死
所以
我們考慮在第 i + 1,(i > 0) 回合 A 剛好可以擊殺 B,即在第 i 回合 A 無法擊殺 B。那么在第 i 回合 B
一定可以擊殺 A。所以只要 A 第一回合無法擊殺 B,那么 B 一定贏。
因此結論可以表示為:
1. 如果 A 第一回合被扣血死,那么 B 贏;
2. 如果 A 第一回合能打死 B,或者使 B 只剩一點血,那么 A 贏;
3. 其他情況 B 贏。
要注意1這種情況就是都只有1滴血這種情況
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while(T -- ) { int n, k; cin >> n >> k; if(n == 1) { cout << "freesin" << endl; continue; } if(n - k <= 1) cout << "pllj" << endl; else cout << "freesin" << endl; } return 0; }