AtCoder Regular Contest 177 A - C

link

赛时:300 + 400, rank 2001 吊车尾

A - Exchange

简单模拟,没有多想什么,直接贪心,总是先保证用较大的数去覆盖花销,应该是一种有解且较快的方法,同时显然的,我对花销从大到小进行排序,一遍过。

#include <bits/stdc++.h>
#define re register int 
using namespace std;
const int N = 20;
struct number
{
	int w, v;
}num[N];
int n, shop[N], tot, need;
bool cmp(int i, int j) { return i > j; }

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	num[1].w = 1, num[2].w = 5, num[3].w = 10, num[4].w = 50, num[5].w = 100, num[6].w = 500;
	for (re i = 1; i <= 6; i ++) 
	{
		cin >> num[i].v;
		tot += num[i].v * num[i].w;
	}
	cin >> n;
	for (re i = 1; i <= n; i ++) 
	{
		cin >> shop[i];
		need += shop[i];
	}
	if (tot < need)
	{
		cout << "No\n";
		return 0;
	}
	sort(shop + 1, shop + n + 1, cmp);
	
	for (re i = 1; i <= n; i ++)
		for (re j = 6; j >= 1; j --)
		{
			if (!shop[i]) break;
			while (num[j].v > 0 && shop[i] - num[j].w >= 0) 
			{
				shop[i] -= num[j].w; 
//				cout << i << ' ' << j << ' ' << shop[i] << '\n';
				num[j].v --;
			}
		}
/*	
	for (re i = 1; i <= n; i ++)
		cout << shop[i] << ' ';
*/	
	bool flag = false;
	for (re i = 1; i <= n; i ++)
		if (shop[i]) 
		{
			flag = true;
			break;
		}	
	if (flag) cout << "No\n";
	else cout << "Yes\n";
	
	return 0;
}

B - Puzzle of Lamps

找规律的题目,一排灯有状态 0(OFF) 或 1(ON),有开(A:0->1)关(B:1->0),规定从左至右操作依次开灯或关灯,初始全部关闭,给出末状态,反推开关方案。

最重要的性质是,开关是规定从左至右依次控制灯

意思就是,若 单独 讨论 i 位置上的灯为状态 1,它必然需要进行 i 次操作 A 得到。

显然,在 n 位置的灯满足这个讨论,

而在之前的灯的状态可能收到后边的灯的状态的影响,分类讨论即可,设当前 i 位置状态为 p,先前灯的状态为 q

  • 若 p = 0,
    • 若 q = 0,直接继承,无需操作;
    • 若 q = 1,需要进行 i 次操作 B 使 i 灯泡由 1 -> 0;
  • 若 p = 1,
    • 若 q = 1, 直接继承,无需操作;
    • 若 q = 0,需要进行 i 次操作 A 使 i 灯泡由 0 -> 1;
#include <bits/stdc++.h>
#define re register int 
using namespace std;
const int N = 50, M = 1e6 + 10;
int n, cnt;
string s;
char ans[M];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	cin >> n;
	cin >> s;
	int last = -1;
	for (re i = n - 1; i >= 0; i --)
	{
		if (i == n - 1)
		{
			if (s[i] == '0') last = 0;
			if (s[i] == '1')
			{
				last = 1;
				for (re k = 1; k <= n; k ++) ans[++ cnt] = 'A';
			}
		}
		else
		{
			if (s[i] == '0') 
			{
				if (last == 0) continue;
				else
				{
					last = 0;
					for (re k = 1; k <= i + 1; k ++) ans[++ cnt] = 'B';
				}
			}
			else
			{
				if (last == 1) continue;
				else
				{
					last = 1;
					for (re k = 1; k <= i + 1; k ++) ans[++ cnt] = 'A';
				}
			}
		}
	}
	cout << cnt << '\n';
	for (re i = 1; i <= cnt; i ++) cout << ans[i];
	cout << '\n';
	
	return 0;
}

C - Routing

这题我一开始想用 dfs 做的,求四个点分别所在的连通快,再求 (1, 1) 与 (n, n) 所在连通块的最短距离,(n, 1) 和 (1, n) 同理,同时我也在想这两种路径会不会互相影响,

后边发现求最短距离不好做,会不会影响,能不能单独求解也没想明白,花好多时间结果打了个屎山代码。。。


首先要想明白 红线 和 蓝线 的路径求解会不会相互影响?

认为红色路径经过蓝色点变成的紫色点为需要 1 的花销,发现,红色路径走红点不产生花销,走蓝点产生 1 的花销,而再对于去求蓝色路径,并不关心蓝点是否变为紫点,关心的是会产生花销为 1 的红点,因为求红色路径并不改变图中的红点,所以 红色路径和蓝色路径的花销是相互独立的

所以,这题就可以简化为求两点间的最小花销,

可以用 最短路 求解,对相邻点建双向边,同色点边权为 0,异色点边权为 1,跑一遍 dijkstra 即得到最小花销。

image

一开始,我还很死板地闷想这双向边怎么快速地建,

其实在矩阵里完全不必用链式前向星还真去建个边出来,直接在 bfs 里走图就是了,这是我思维不足的地方。

注意:使用 tuple 时,把要比较的值放在第一维。

#include <bits/stdc++.h>
#define re register int 
using namespace std;
typedef tuple<int, int, int> tp;
const int N = 510, inf = 0x3f3f3f3f;
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
char g[N][N];
int n, res1, res2, dist[N][N];
bool vis[N][N];
priority_queue< tp, vector<tp>, greater<tp> > q;

inline int work(int sx, int sy, int ex, int ey, char c)
{
	memset(vis, false, sizeof(vis));
	for (re i = 1; i <= n; i ++)
		for (re j = 1; j <= n; j ++) dist[i][j] = inf;
		
	dist[sx][sy] = 0;
	q.push(make_tuple(0, sx, sy));
	
	while (!q.empty())
	{
		int x = get<1>(q.top()), y = get<2>(q.top());
		q.pop();
		if (vis[x][y]) continue;
		vis[x][y] = true;
		
		for (re i = 0; i < 4; i ++)
		{
			int tx = x + dx[i], ty = y + dy[i];
			if (tx < 1 || tx > n || ty < 1 || ty > n) continue;
			
			int w = (g[tx][ty] == c ? 0 : 1);
			if (dist[x][y] + w < dist[tx][ty])
			{
				dist[tx][ty] = dist[x][y] + w;
				q.push(make_tuple(dist[tx][ty], tx, ty));
			}
		}
	}
/*	
	for (re i = 1; i <= n; i ++)
	{
		for (re j = 1; j <= n; j ++) cout << dist[i][j] << ' ';
		cout << '\n';
	}	
*/	
	return dist[ex][ey];
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	cin >> n;
	for (re i = 1; i <= n; i ++)
		for (re j = 1; j <= n; j ++) cin >> g[i][j];
	res1 = work(1, 1, n, n, 'R');
	res2 = work(1, n, n, 1, 'B');
	
	cout << res1 + res2 << '\n';
	
	return 0;
}
posted @ 2024-05-13 21:45  Zhang_Wenjie  阅读(70)  评论(0)    收藏  举报