Codeforces Round #695
作者:互联网
Codeforces Round #695 (Div. 2)
B. Hills And Valley
题解:模拟改变每个数, 对于 a [ i ] a[i] a[i]计算 变成 a [ i − 1 ] a[i - 1] a[i−1]的贡献, 和 a [ i + 1 ] a[i + 1] a[i+1]的贡献,枚举每个数, 最后取最优的就好了。
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 7;
int a[N], n;
int cal(int pos) {
if (a[pos] > a[pos - 1] && a[pos] > a[pos + 1]) {
return 1;
} else if (a[pos] < a[pos - 1] && a[pos] < a[pos + 1]) {
return 1;
}
return 0;
}
int work(int pos) {
int ans = 0;
if (pos > 2 && pos < n - 1) {
ans += cal(pos);
ans += cal(pos - 1);
ans += cal(pos + 1);
} else if (pos < n - 1) {
ans += cal(pos);
ans += cal(pos + 1);
} else if (pos > 2){
ans += cal(pos);
ans += cal(pos - 1);
} else if (pos == 2 && pos == n - 1) {
ans += cal(pos);
}
return ans;
}
void solve(int j) {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
if (n < 3) {
cout << 0 << endl;
} else {
int ans = 0;
for (int i = 2; i < n; i++) {
ans += cal(i);
}
int res = 0;
for (int i = 2; i < n; i++) {
int temp = a[i];
int cnt = work(i);
a[i] = a[i - 1];
int cnt1 = work(i);
a[i] = a[i + 1];
int cnt2 = work(i);
a[i] = temp;
res = max(res, cnt - min(cnt1, cnt2));
}
cout << ans - res << endl;
}
}
int main() {
int t; cin >> t;
for (int j = 1; j <= t; j++) {
solve(j);
}
}
C. Three Bags
题解:总共有 3 ∗ n 3 * n 3∗n 的物品, 也就是说要操作 3 ∗ n − 1 3 * n - 1 3∗n−1 次才结束, 把每次操作看成一条边, 也就是 3 ∗ n − 1 3 * n - 1 3∗n−1次操作刚好构成一颗节点为 3 ∗ n 3 * n 3∗n的树。
例如:
这个树表示的操作是 (4, 3), (3, 2), (2, 1)然后答案就是 a − b + c − d a - b + c - d a−b+c−d,也就是深度为奇数的要减(根节点的深度为0), 要向总共的和最大,就要减最少。
因为,相同背包的物品不能进行操作,所以要满足下面条件的任意一个:
-
如果奇数层为同一种背包的物品,那么这种背包的所有物品都必须在奇数层。这个很好证明, 如果奇数只会一种背包的物品,且还有这种背包的物品在偶数层,那就没法合并了。
-
奇数层至少含有两种背包。
有了这个答案就很好构造了,要么取每一种背包和最小的, 要么从三种背包种取两个不同种背包最小的。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 7;
typedef long long ll;
ll a[4][N], n1, n2, n3, t;
void solve() {
ll sum1 = 0, sum2 = 0, sum3 = 0, ans;
cin >> n1 >> n2 >> n3;
for (int i = 1; i <= n1; i++) {
cin >> a[1][i];
sum1 += a[1][i];
}
sort(a[1] + 1, a[1] + n1 + 1);
for (int i = 1; i <= n2; i++) {
cin >> a[2][i];
sum2 += a[2][i];
}
sort(a[2] + 1, a[2] + n2 + 1);
for (int i = 1; i <= n3; i++) {
cin >> a[3][i];
sum3 += a[3][i];
}
sort(a[3] + 1, a[3] + n3 + 1);
ans = sum1 + sum2 + sum3;
ll cnt = a[1][1] + a[2][1] + a[3][1];
cnt = cnt - max(max(a[1][1], a[2][1]), a[3][1]);
ans = ans - 2 * min(min({sum1, sum2, sum3}), cnt);
cout << ans << endl;
}
int main() {
t = 1;
while (t--) {
solve();
}
}
D. Sum of Paths
题解:
设 d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0]表示到达 i i i点还剩 j j j步所走的贡献是多少, d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1]表示,从其它点 到达 i i i点还剩 j j j步,有多少条路径。
s u m [ i ] sum[i] sum[i]表示 第 i i i个节点走了多少次。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 7;
typedef long long ll;
const ll mod = 1e9 + 7;
ll n, k, q, a[N], dp[N][N][2];
ll sum[N];
int main() {
cin >> n >> k >> q;
for (int i = 1; i <= n; i++) {
cin >> a[i];
dp[i][0][0] = a[i];
dp[i][0][1] = 1;
}
for (int i = 1; i <= k; i++) {
for (int j = 1; j <= n; j++) {
if (j == 1) {
dp[j][i][0] = dp[j + 1][i - 1][0] + dp[j + 1][i - 1][1] * a[j];
dp[j][i][1] = dp[j + 1][i - 1][1];
} else if (j == n) {
dp[j][i][0] = dp[j - 1][i - 1][0] + dp[j - 1][i - 1][1] * a[j];
dp[j][i][1] = dp[j - 1][i - 1][1];
} else {
dp[j][i][0] = dp[j - 1][i - 1][0] + dp[j - 1][i - 1][1] * a[j];
dp[j][i][1] = dp[j - 1][i - 1][1];
dp[j][i][0] += dp[j + 1][i - 1][0] + dp[j + 1][i - 1][1] * a[j];
dp[j][i][1] += dp[j + 1][i - 1][1];
}
dp[j][i][0] %= mod;
dp[j][i][1] %= mod;
}
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
ans += dp[i][k][0];
ans %= mod;
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= k; j++) {
sum[i] += dp[i][j][1] * dp[i][k - j][1];
sum[i] %= mod;
}
}
while (q--) {
ll x, y; scanf("%lld %lld", &x, &y);
if (y >= a[x]) {
ll cnt = y - a[x];
ll cat = (cnt % mod * sum[x] % mod) % mod;
ans = ans + cat;
ans = ans % mod;
} else {
ll cnt = a[x] - y;
ll cat = (cnt % mod * sum[x] % mod) % mod;
ans = (ans - cat + mod) % mod;
}
a[x] = y;
printf("%lld\n", ans);
}
}
E. Distinctive Roots in a Tree
题解:
这题就比较难想。
我可以先求出非法的节点, 然后剩下来的就是合法的点。
哪些点是非法的呢?
- 如果节点 u u u 的权值,除了节点 u u u孩子节点权值,其它点有与 u u u权值相等的点,那么可以证明节点 u u u和它的孩子节点全部不合法。(这里的孩子节点包含儿子节点,孙子节点, 孙子的孙子……)
- 如果有一个儿子节点 v v v, 其父亲节点为 u u u是,如果 v v v的孩子节点中有一个权值和父亲节点的权值相等, 那么可以证明, 除了 u u u的孩子节点,其它节点都不合法。
至于为啥?仔细想一下就明白了。
有了这个我没就可以把不合法的给去掉,剩下来的一定是合法的。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;
int a[N], n, all[N];
vector<int> g[N], v;
map<int, int> mp[N];
int get_id(int x) {
return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}
int id[N], sum[N], vis[N], sz[N], top = 1;
int cat[N];
int merge(int x, int y) {
if (mp[x].size() > mp[y].size()) {
for (auto it: mp[y]) {
mp[x][it.first] += it.second;
}
mp[y].clear();
return x;
} else {
for (auto it: mp[x]) {
mp[y][it.first] += it.second;
}
mp[x].clear();
return y;
}
}
void dfs(int u, int fa) {
id[u] = top++;
sz[u] = 1;
mp[cat[u]][a[u]] = 1;
for (int to: g[u]) {
if (to == fa) continue;
dfs(to, u);
sz[u] += sz[to];
if (mp[cat[to]][a[u]]) {
sum[1]++;
sum[id[to]]--;
sum[id[to] + sz[to]]++;
}
cat[u] = merge(cat[u], cat[to]);
}
if (all[a[u]] > mp[cat[u]][a[u]]) {
sum[id[u]]++;
sum[id[u] + sz[u]]--;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
v.push_back(a[i]);
cat[i] = i;
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for (int i = 1; i <= n; i++) {
a[i] = get_id(a[i]);
all[a[i]]++;
}
for (int i = 1; i < n; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
int ans = 0;
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + sum[i];
if (sum[i] == 0) {
ans++;
}
}
cout << ans << endl;
}
标签:ll,695,int,sum,Codeforces,pos,ans,Round,dp 来源: https://blog.csdn.net/weixin_45676038/article/details/112548499