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;
}

posted @ 2023-07-03 12:55  xqy2003  阅读(128)  评论(1)    收藏  举报