1262. 鱼塘钓鱼
分析
最开始在1号鱼塘
在去做的时候, 我们可以先去枚举下最远走到哪个鱼塘, 为什么要这样枚举呢
我们发现在每个鱼塘钓到鱼的数量, 只取决于在这个鱼塘钓鱼的总时间
因此不可能出现折返的情况(先往前走, 钓几分钟, 再回来钓❌)
如果出现折返的情况的话, 我可以改进方案, 直接在第1个鱼塘钓满可以钓的时间, 再去第2个鱼塘钓鱼, 这样我们总时间就会变小
因此不可能往回走, 所以会往前走
所以我们枚举最远到达哪个鱼塘, 那么路上所花的时间就确定了
因此总共的钓鱼时间就确定了, = T(总时间) - 路上的时间
有了总共钓鱼时间, 比如是100
相当于是求每一个鱼塘对应的序列, 每个序列的话, 可以取出若干个数, 总共要取100个数, 在这种情况下, 问我们所有取的数的总和最大是多少
所以总和最大, 就意味着我们要取所有序列 最靠前的那些数
所以剩下的问题就转化为这些单调的数列的最大的前若干个数是多少, 那么就可以用多路归并排序
所以这题考察点就是: 枚举 + 贪心 + 多路归并
时间复杂度的话, 我们先要枚举下鱼塘n,
总时间的话,题目最大给了1000, 因此总时间复杂度nT
多路归并的话, 可以用堆来做, 也可以用循环来做, n比较小, 所以直接用循环
总时间复杂度n^T = 10 0 2 ∗ 1000 100^2 * 1000 1002∗1000 = $10^7 $
code
//1.因为在鱼塘间来回走动会减少钓鱼的总时间,因此只需要确定最远走到哪里,就可以计算出钓鱼的总时间
#include <iostream>
#include <cstring>
using namespace std;
const int N = 110;
int a[N], d[N], l[N], spend[N];//spend表示在该鱼塘花的时间
int get(int k){
return max(0, a[k] - d[k] * spend[k]);
}
int work(int n, int T){// T表示总钓鱼时间
int res = 0;
memset(spend, 0, sizeof spend);
// 多路归并, n条路, 取前T个数, 所以先枚举T, 再枚举每条路
for (int i = 0; i < T; i ++ ){// 枚举T分钟内, 每分钟可以选的最大数
int t = 1;
for (int j = 1; j <= n; j ++ ) // 枚举每个鱼塘
if (get(j) > get(t))
t = j;
res += get(t); // 先加上能钓到的鱼的数量
spend[t] ++; // 钓完后, 该鱼塘钓鱼时间 ++, 顺序不能倒
}
return res;
}
int main(){
int n, T;
cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ ) cin >> d[i];
for (int i = 2; i <= n; i ++ ){
cin >> l[i];
l[i] += l[i - 1];//前缀和记录走到该点的总时间
}
cin >> T;
int res = 0;
for (int i = 1; i <= n; i ++ )//枚举最远走到哪一个点
res = max(res, work(i, T - l[i]));
cout << res << endl;
return 0;
}
312. 乌龟棋
分析
发现一共有120张卡片, 每张卡片的数量不会超过40, 因此可以用4维, 表示当前每张卡片用了多少张
这样状态数量 4 0 4 = 2560000 40^4 = 2560000 404=2560000, 用f[a][b][c][d]表示
考虑下f[a][b][c][d]怎么求, 以最后一张用了什么类型卡片为分界点
然后看下其中每一类的最大值是多少, 最终取max, 就是总共最大值
以最后一张用了c卡片为例:
如果当前跳到了第s个位置, 如果最后一张卡片用了c, 那么倒数第2步一定在s - 3的位置
那么前面这个状态就是f[a][b][c - 1][d] + w_s
状态数量
4
0
4
40^4
404, 状态转移的时间复杂度O(1), 其实没有这么大, 因为总共只有120张, 4个数的和是120, 4个数的乘积最大的话, 那么4个数得相等,
3
0
4
30^4
304
code
#include <iostream>
using namespace std;
const int N = 41, M = 360; // 题目给了总长度350
int f[N][N][N][N];
int n, m;
int w[M];
int b[N];
int main(){
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%d", &w[i]);
for (int i = 0; i < m; i ++ ){ // 注意这里题目是输出每张卡片的类型, 所以先读入卡片的类型x
int x;
scanf("%d", &x);
b[x - 1] ++ ;
}
for (int A = 0; A <= b[0]; A ++ )
for (int B = 0; B <= b[1]; B ++ )
for (int C = 0; C <= b[2]; C ++ )
for (int D = 0; D <= b[3]; D ++ ){
int score = w[A * 1 + B * 2 + C * 3 + D * 4];
int& v = f[A][B][C][D];
v = score; // 因为有可能4种dp的方案都不存在, 所以先用score初始化v, 比如第1个格子, 就不存在4种方案
if (A) v = max(v, f[A - 1][B][C][D] + score);
if (B) v = max(v, f[A][B - 1][C][D] + score);
if (C) v = max(v, f[A][B][C - 1][D] + score);
if (D) v = max(v, f[A][B][C][D - 1] + score);
}
cout << f[b[0]][b[1]][b[2]][b[3]] << endl;
return 0;
}
211. 计算系数
分析
C
a
b
=
C
a
−
1
b
+
C
a
−
1
b
−
1
C_a^b = C_{a - 1}^b + C_{a - 1}^{b - 1}
Cab=Ca−1b+Ca−1b−1
推到思路: 固定一个数, 不选这个数的话, 那么就是从a - 1个中选b个;选这个数的话, 就是剩余a - 1中选b - 1个数
code
#include <iostream>
using namespace std;
const int N = 1010, MOD = 10007;
int C[N][N];
int power(int a, int b){
a %= MOD;
int res = 1;
while (b -- ) res = res * a % MOD;
return res;
}
int main(){
int a, b, k, n, m;
cin >> a >> b >> k >> n >> m;
for (int i = 0; i <= k; i ++ )
for (int j = 0; j <= i; j ++ )
if (!j) C[i][j] = 1;
else C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
cout << C[k][n] * power(a, n) % MOD * power(b, m) % MOD << endl;
return 0;
}
496. 机器翻译
分析
code
#include <iostream>
#include <queue>
using namespace std;
const int N = 1010;
queue<int> q;
bool st[N];
int n, m;
int main(){
scanf("%d%d", &m, &n);
int res = 0;
while (n -- ) {
int x;
cin >> x;
if (!st[x]) {
if (q.size() == m) {
st[q.front()] = false;
q.pop();
}
q.push(x);
st[x] = true;
res ++;
}
}
cout << res << endl;
return 0;
}
148. 合并果子
分析
用堆来做
code
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int, vector<int>, greater<int>> heap;
int n;
int main(){
scanf("%d", &n);
while (n -- ) {
int x;
scanf("%d", &x);
heap.push(x);
}
int res = 0;
while (heap.size() > 1){
int a = heap.top(); heap.pop();
int b = heap.top(); heap.pop();
a += b;
heap.push(a);
res += a;
}
cout << res << endl;
return 0;
}