CCF CAT
Best Travel Plans
枚举在哪个城市停止旅行 , 这样我们在路程上花费的时间就确定了 , 同时确定了在活动上花费的时间
对于活动花费的时间,我们贪心选择每一秒的最优值即可
#include <bits/stdc++.h>
using ll = long long;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n,m;
std::cin >> n >> m;
std::vector<int> t(n + 1) , e(n + 1) , d(n + 1);
for(int i = 2 ; i <= n ; ++i)
std::cin >> t[i];
for(int i = 1 ; i <= n ; ++i)
std::cin >> e[i];
for(int i = 1 ; i <= n ; ++i)
std::cin >> d[i];
std::vector<std::vector<int>> p(n + 1);
for(int i = 1 ; i <= n ; ++i) {
for(int j = 0 ; e[i] - j * d[i] > 0 && j <= m; ++j) {
p[i].emplace_back(e[i] - j * d[i]);
}
}
int travel = 0 , ans = 0;
for(int i = 1 ; i <= n ; ++i) { //枚举在哪座城市停止旅行
travel += t[i];
int remain = m - travel;
if(remain <= 0) break;
std::vector<int> pos(n + 1 , 0);
int sum = 0;
for(int j = 1 ; j <= remain ; ++j) { //枚举每一秒时间怎么用
int mx = 0 , id ;
for(int k = 1 ; k <= i ; ++k) {
if(pos[k] > p[k].size() - 1) continue;
if(p[k][pos[k]] > mx) {
mx = p[k][pos[k]] , id = k;
}
}
sum += mx , pos[id]++; //每一个城市的活动都需要连续地接上
}
ans = std::max(ans , sum);
}
std::cout << ans << '\n';
return 0;
}
Hearthstone
想起这个题
\(dp[i][x][y] : 第 i 位法力消耗值为 x , 第 i - 1 为法力消耗值为 y时 , 前 i 位填数的最大幸运值\)
由于卡牌是环形 (第一反应是切环为链) , 第 \(n\) 位的填数合法性的判断要考虑第\(1\)位,第\(2\)位的情况
我们不能让第 \(n\) 次转移由第 \(1\) , \(2\)次状态转移过来 , 不如枚举前两位将其固定再 \(dp\)
#include <bits/stdc++.h>
using ll = long long;
const int N = 1E5 + 5;
ll dp[N][3][3];
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<std::array<int,3>> val(n + 1);
for(int i = 1 ; i <= n ; ++i) {
for(int j = 0 ; j < 3 ; ++j)
std::cin >> val[i][j];
}
ll ans = -0x3f;
for(int p = 0 ; p < 3 ; ++p) {
for(int q = 0 ; q < 3 ; ++q) {
if(p == q) continue;
memset(dp , -0x3f , sizeof dp);
dp[2][p][q] = val[1][p] + val[2][q];
for(int i = 3 ; i <= n ; ++i) {
for(int j = 0 ; j < 3 ; ++j) {
for(int k = 0 ; k < 3 ; ++k) {
for(int w = 0 ; w < 3 ; ++w) {
if( (j < k && w < k) || (j > k && w > k) )
dp[i][k][w] = std::max(dp[i][k][w] , dp[i - 1][j][k] + val[i][w]);
}
}
}
}
for(int j = 0 ; j < 3 ; ++j)
for(int k = 0 ; k < 3 ; ++k) {
if( (k < p && q < p) || (k > p && q > p)) {
if( (j < k && p < k) || (j > k && p > k) ) {
ans = std::max(ans , dp[n][j][k]);
}
}
}
}
}
std::cout << ans << '\n';
return 0;
}
Hotpot
感觉这个方法很典 ( 计数类 , 期望类 \(dp\) )
\(dp[i]\) 代表有 \(i\) 的位置坐人的总方案数
转移 : \(dp[i] = dp[i - 1] + dp[i - 2]\)
$dp[i - 1] : $ 第 \(i\) 位置不坐人 , 等价只有 \(i - 1\) 个位置
$dp[i - 1] : $ 第 \(i\) 位置坐人 , 那么第 \(i - 1\) 位置不坐人 , 那么 \(i \space , i - 1\)位置确定 , 等价于 \(dp[i - 2]\) 的方案
#include <bits/stdc++.h>
using ll = long long;
const ll mod = 1E9 + 7;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<ll> dp(n + 1);
dp[1] = 2 , dp[2] = 3;
for(int i = 3 ; i <= n ; ++i)
( dp[i] = dp[i - 1] + dp[i - 1] ) %= mod;
std::cout << dp[n] * dp[n] % mod;
return 0;
}
Mystery Sailing Challenge
类似于牛客小白月赛 \(75 D\)
赛后复盘时 , 认为 \(dis[u][i][modi]\) 可以简化为 \(dis[u][modi]\) 的状态 , 认为入边 \(i\) 仅是转移的方式 , \(modi\)才是有效状态 , 再仔细一想 , 这样干嘛不把 \(modi\) 也去除变成 \(dis[u]\) , 再想想每次的转移方式均依赖于 \(i \space ,modi\) , 可能此时的 \(dis[u]\) , 但转移的代价可以很小 , 但如果只有 \(dis[u]\) 一个状态 , 在$ if(d > dis[u]) $ 中此次转移就会结束
#include <bits/stdc++.h>
using ll = long long;
const int N = 1E3 + 5 , M = 2E4 + 5;
const ll INF = 1E18;
ll dis[N][M][2];
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n,m;
std::cin >> n >> m;
std::vector<int> edge(m + 1);
std::vector<std::vector<std::array<int,3>> > g(n);
for(int i = 1 ; i <= m ; ++i) {
int u,v,w;
std::cin >> u >> v >> w;
--u ; --v;
g[u].push_back({v , w , i});
g[v].push_back({u , w , i});
edge[i] = w;
}
using T = std::array<ll , 4>;
std::priority_queue<T,std::vector<T>,std::greater<T> > q;
memset(dis , 0x3f , sizeof dis);
std::vector<ll> ans(n , -1);
dis[0][0][0] = 0;
q.push({0 , 0 , 0 , 0});
while(!q.empty()) {
auto f = q.top() ; q.pop();
ll d = f[0] , u = f[1] , i = f[2] , modi = f[3];
if ( dis[u][i][modi] < d ) {
continue;
}
if (ans[u] == -1 || ans[u] > d) {
ans[u] = d;
}
for(auto t : g[u]) {
int v = t[0] , w = t[1] , j = t[2];
if(i != 0 && modi == 0) {
if (w > edge[i] && w % edge[i] == 0) {
ll nw = (1ll * w / edge[i] - 1) * edge[i];
if(dis[v][j][1] > dis[u][i][0] + nw) {
dis[v][j][1] = dis[u][i][0] + nw;
q.push({dis[v][j][1] , v , j , 1});
}
}
}
if(dis[v][j][0] > dis[u][i][modi] + w) {
dis[v][j][0] = dis[u][i][modi] + w;
q.push({dis[v][j][0] , v , j , 0});
}
}
}
for(int i = 0 ; i < n ; ++i) {
std::cout << ans[i] << " \n"[i == n - 1];
}
return 0;
}

浙公网安备 33010602011771号