思路:
首先考虑最暴力的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; }