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;
}
标签:Onsite,const,EDG,XXII,int,ll,pos,num,id
From: https://www.cnblogs.com/yaqu-qxyq/p/16917839.html