The 2021 CCPC Guilin Onsite (XXII Open Cup, Grand Prix of EDG

https://codeforces.com/gym/103409/problem/B

B. A Plus B Problem —————数据结构(set)

题意

给你两个n位的数a, b(有前导零), c是a+b的结果(最高位的进位已省略)
q次询问 id pos num代表将第几行的第pos个数修改为num
输出修改后 第三行修改后当前位置的数x 和 三行一共变化的数字的个数cnt

思路

设c数组为每位上a[i]和b[i]的和对10的余数,额外记录一个cn代表后面是否有进位。
分几种情况:
1.就改的数就是原来该位置上的数 那么就没有改变任何一个数 cnt = 0
2.修改前后进位情况一样 不会影响pos位置以外的其他数 cnt = 2,x = 修改后的余数+cn
3.修改前后进位情况不一样 影响前面若干要连续进位的数 即该位置前有几个连续的9的个数tot, cnt = tot + 2 + 1,x = 修改后的余数+cn
然后用set乱搞一下就好了 具体见代码注释

#include<bits/stdc++.h>
#define ll long long
#define m_p make_pair
using namespace std;

const ll N = 1e6 + 10;
const ll M = 5e6 + 10;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;

int n, q;
//这样开数组便于后续处理
int a[2][N];
string s1, s2;
set<int>st;

//计算后面是否有进位
int cal_suf(int p) {
	auto it = st.upper_bound(p);
	if (it == st.end()) return 0;
	return (a[0][*it] + a[1][*it]) / 10;
}

//计算前面有多少个连续的9
int cal_pre(int p) {
	auto it = st.lower_bound(p);
	if (it == st.begin()) return p - 1;
	it--;
	return p - (*it);
}

//更新set 和修改的数
void update(int id, int pos, int num) {
	if (a[id][pos] + a[id ^ 1][pos] == 9 && num + a[id ^ 1][pos] != 9)
		st.insert(pos);
	else if (a[id][pos] + a[id ^ 1][pos] != 9 && num + a[id ^ 1][pos] == 9)
		st.erase(pos);

	a[id][pos] = num;
}

void solve()
{
	cin >> n >> q;
	cin >> s1 >> s2;

	s1 = " " + s1;
	s2 = " " + s2;

	for (int i = 1; i <= n; i++) {
		a[0][i] = s1[i] - '0';
		a[1][i] = s2[i] - '0';
                //将余数不是9的位置插入Set中
		if ((a[0][i] + a[1][i]) % 10 != 9) st.insert(i);
	}

	while (q--) {
		int id, pos, num;
		cin >> id >> pos >> num;
		id--;

		int cn = 0;
		cn = cal_suf(pos);
                //前后修改没变化
		if (num == a[id][pos]) {
			cout << (a[id][pos] + a[id ^ 1][pos] + cn) % 10 << " " << 0 << "\n";
			continue;
		}
                
                //修改前后进位相同
		if (a[id][pos] + a[id ^ 1][pos] + cn >= 10 && a[id ^ 1][pos] + num + cn >= 10 || a[id][pos] + a[id ^ 1][pos] + cn < 10 && a[id ^ 1][pos] + num + cn < 10) {
			cout << (num + a[id ^ 1][pos] + cn) % 10 << " " << 2 << "\n";
			update(id, pos, num);
			continue;
		}
                
                //修改前后进位不同
		cout << (num + a[id ^ 1][pos] + cn) % 10 << " " << cal_pre(pos) + 2 << "\n";
		update(id, pos, num);
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int _t = 1;

    //cin >> _t;
	while (_t--)
		solve();
	return 0;
}

K Tax ————bfs + dfs

题意

n(n<=50)个城市 m条双向路 m个城市 第i条路是由第ci个公司造的,第k次进过第x公司造的路就要收费&k * cost[ci]&
每次走的必须是最短路
输出n - 1行 代表从一号城市走到底i + 1号城市最小要收费多少

思路

因为一定要走最短路 所以我们可以先求出最短路 然后很久最短路建一个dag图。
又因为题目给出的n很小 我们可以直接dfs 找最优解 复杂的为O(2^(n / 2))

#include<bits/stdc++.h>
#define ll long long
#define m_p make_pair
using namespace std;

const ll N = 3000 + 5;
const ll M = 5e6 + 10;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;

ll n, m, a[N];
ll dis[N], ans[N];
int vis[N], cnt[N];
pair<pair<int, int>, int>e[N];
vector<pair<int, int>>g[N], g2[N];
string s;

void dij(int s) {
	for (int i = 1; i <= n; i++) {
		dis[i] = INF;
		vis[i] = 0;
	}
	priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>>q;
	dis[s] = 0;
	q.push({ dis[s], s });

	while (!q.empty()) {
		auto [w, now] = q.top();
		q.pop();
		if (vis[now]) continue;
		vis[now] = 1;

		for (auto [to, w2] : g[now]) {
			if (dis[to] > dis[now] + 1) {
				dis[to] = dis[now] + 1;
				q.push({ dis[to], to });
			}
		}
	}
}

void dfs(int x, ll val) {
	for (auto [to, c] : g2[x]) {
		cnt[c]++;
		ans[to] = min(ans[to], val + cnt[c] * a[c]);
	    dfs(to, val + cnt[c] * a[c]);
		cnt[c]--;
	}
}

void solve()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		ans[i] = INF;
	for (int i = 1; i <= m; i++)
		cin >> a[i];

	for (int i = 1, u, v, c; i <= m; i++) {
		cin >> u >> v >> c;
		e[i] = { {u, v}, c };
		g[u].push_back({ v, c });
		g[v].push_back({ u, c });
	}

	dij(1);
        //最短路建图
	for (int i = 1; i <= m; i++) {
		int u = e[i].first.first;
		int v = e[i].first.second;
		int c = e[i].second;

		if (dis[u] - dis[v] == 1)
			g2[v].push_back({ u, c });
		if (dis[v] - dis[u] == 1)
			g2[u].push_back({ v, c });
	}

	dfs(1, 0);

	for (int i = 2; i <= n; i++)
		cout << ans[i] << "\n";
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	int _t = 1;

    //cin >> _t;
	while (_t--)
		solve();
	return 0;
}
posted @ 2022-11-23 11:57  Yaqu  阅读(87)  评论(0编辑  收藏  举报