CF1060 CD
仪表板 - Codeforces 第 1060 轮(第 2 组) - Codeforces — Dashboard - Codeforces Round 1060 (Div. 2) - Codeforces
C1/C2. No Cost Too Great
题意:给定i个数和对应的操作成本,每次操作可以让数+1,使数组存在任意两数不互质的最小成本是多少?
easy的操作成本全为1,hard的操作成本覆盖(1—109)(1—10^9)(1—109) 。
思路:对于easy版本,首先容易想到只有3种情况:
- ans=0。初始就存在 $ \gcd(a[i],a[j])\neq1$ 。
- ans=1。对一个数+1后,存在$ \gcd(a[i],a[j])\neq1$。
- ans=2。都不满上述情况,说明是全为奇数的数组,对任意两个奇数+1凑出 gcd=2\gcd=2gcd=2即可。
现在考虑怎么快速判断数组是否存在任意两数不互质。
不互质即有公因数,我们可以考虑分解质因数,再用map记录,如果第二次出现,说明有重复可处理情况一。
至于情况二,特殊只在于改变了某个数x,所以我们在map中减去x的因数,判断x+1是否满足,最后加回来即可。
vector<int> e[N + 1];
void solve()
{cin >> n;rep(1, i, n){cin >> a[i];}rep(1, i, n){cin >> b[i];}map<int, int> mp;rep(1, i, n){for (auto j : e[a[i]]){mp[j]++;if (mp[j] > 1){cout << 0;re;}}}rep(1, i, n){for (auto j : e[a[i]]){mp[j]--;}for (auto j : e[a[i] + 1]){if (mp[j] > 0){cout << 1;re;}}for (auto j : e[a[i]]){mp[j]++;}}cout << 2;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);int T;T = 1;for (int i = 2; i <= N; i++){if (e[i].size())continue;for (int j = i; j <= N; j += i){e[j].push_back(i);}}cin >> T;while (T--){solve();cout << '\n';}return 0;
}
现在考虑hard版本:
同easy版本我们可以先确定上界为 c[0]+c[1]c[0]+c[1]c[0]+c[1](最小的两个代价)。
其他情况都没有区别,只是多了一种情况:对最小代价的那个数,可以操作多次直到产生答案。
为什么这种情况可以?
首先为什么是最小代价,如果加入对其他数的操作,那么必然劣于上界 c[0]+c[1]c[0]+c[1]c[0]+c[1],所以不用考虑。
然后如果 c[0]<<<c[1]c[0]<<<c[1]c[0]<<<c[1],当代价差距很大时,这种情况可能变成答案。
比如数组 7 9,代价为1 100。最优解显然是操作 7 两次,代价为2。
void solve()
{cin >> n;rep(1, i, n){cin >> a[i];}int pos = 0; //因为后面要排序,记录一下代价最小的位置int minn = 1e18;rep(1, i, n){cin >> b[i];c[i] = b[i];if (b[i] < minn){minn = b[i];pos = i;}}map<int, int> mp;rep(1, i, n){for (auto j : e[a[i]]){mp[j]++;if (mp[j] > 1){cout << 0;re;}}}sort(c + 1, c + 1 + n);ans = c[1] + c[2];rep(1, i, n){for (auto j : e[a[i]]){mp[j]--;}for (auto j : e[a[i] + 1]){if (mp[j] > 0){ans = min(ans, b[i]);}}for (auto j : e[a[i]]){mp[j]++;}}vector<int> v;rep(1, i, n){if (i == pos)continue;for (auto i : e[a[i]]){v.emplace_back(i);}}for (auto i : v) //枚举所有可能的质因数{num = i - (a[pos] % i); //需要的操作次数if (num == i)num = 0;ans = min(ans, b[pos] * num);}cout << ans;/* rep(1, i, n){a[i] = b[i] = c[i] = 0;} */
}
D. Catshock
题意:小猫每次可以随机地走到当前的相邻节点,1表示走,2表示删去x节点。注意不能连续两次都删节点。
构造一个行动路线,保证小猫能从起点1走到终点n,行动次数<=3*n。
思路:我们考虑对节点分奇偶层,即使是随机地走,也能保证在奇数位置删去偶数位置不会出现问题。
考虑哪些点需要被删掉以及题目要求的3*n的限制能提供什么思路?
由于不能连续删去,当我们已经删去一个偶节点且当前处于奇节点,并且下一次还想删偶节点,显然是最麻烦的操
作了,只需要连续走两步走到奇节点再删即可,这样刚好是3步(1 1 2)不会超出限制次数。
我们可以以终点为dfs起点,如果不是终点就加入删除列表,然后根据当前位置和待删除点深度的奇偶模拟即可。
void solve()
{cin >> n;vector<int> dep(n + 1);vector<int> v;rep(1, i, n - 1){cin >> x >> y;e[x].emplace_back(y);e[y].emplace_back(x);}auto dfs = [&](this auto self, auto u, auto fa) -> void{for (auto i : e[u]){if (i != fa){dep[i] = dep[u] + 1;self(i, u);}}if (u != n)v.emplace_back(u);};dfs(n, 0);int st = dep[1] % 2;vector<int> res;for (auto i : v){res.emplace_back(0);st ^= 1;if (st == dep[i] % 2){res.emplace_back(0);st ^= 1;}res.emplace_back(i);}cout << res.size() << '\n';for (auto i : res){if (i){cout << 2 << ' ' << i;}else{cout << 1;}cout << '\n';}rep(1, i, n){e[i].clear();}
}
