D. Palindromes Coloring
题目概述:
给定一个字符串,需要找到
k
k
k 个长度相同的回文子串,其中 一个字串中的字符可以交换位置,求每个字串长度的最大值。
思路:
因为字串中的字符可以交换位置,只需考虑回文串的组成即可。
如果含有偶数个相同的字符,则一定可以组成一个回文串,将偶数个的字符组成
k
k
k 个回文串之后,统计剩余字符的数量,看剩下的字符是否可以添加到每一个字符串的中间,如果可以则长度可以 + 1。
(注意剩余的字符应该是由两部分组成, 1.非偶数个字符 2.分成 k 份后剩下的字符)
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
void solve() {
int n, k;
string str;
cin >> n >> k >> str;
map<char, int> cnt;
for(auto t : str) {
cnt[t] ++;
}
int lenth = 0, leave = 0;
for(auto [l, r] : cnt) {
lenth += r / 2;
leave += r % 2;
}
int ans = 2 * (lenth / k);
leave += 2 * (lenth % k);
if(leave >= k) ans ++;
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) solve();
}
C. Monsters And Spells
题目概述:
题目内容可以抽象成在
x
x
x 坐标轴上 画
y
=
x
y = x
y=x 的函数,要求覆盖到所有点,并且
∑
0
n
y
\sum _0^ny
∑0ny 最小
思路:
当满足了一个点
i
i
i 的高度后,如果后一个点
j
j
j 的高度 大于
(
j
−
i
+
h
[
i
]
)
(j - i + h[i])
(j−i+h[i]) 时,这条线就需要重新画,因而后面的点会影响前面点的答案,所以我们先倒着做一次,如果出现上述情况,则直接将
h
[
i
]
h[i]
h[i] 的高度提高到
(
h
[
j
]
−
(
j
−
i
)
)
(h[j] - (j - i))
(h[j]−(j−i)),显然这样是不会影响最终答案的,然后再正着做一次。
正着做的应当是当
i
,
j
i, j
i,j 两个点之间的距离满足需要的高度时,直接画线,当不满足时,沿着点
i
i
i 的高度向后画,如果这样画出的高度
h
>
h
[
j
]
h > h[j]
h>h[j] 避免影响后面的答案就直接将
h
[
j
]
h[j]
h[j] 提高到
h
h
h
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
struct Monster {
int k, h;
}m[110];
int sum(int l, int r) {
if(l == r) return l;
return (l + r) * (r - l + 1) / 2;
}
void solve() {
int n;
cin >> n;
for(int i = 1; i <= n; i ++) cin >> m[i].k;
for(int i = 1; i <= n; i ++) cin >> m[i].h;
for(int i = n - 1; i; i --) {
m[i].h = max(m[i].h, m[i + 1].h - (m[i + 1].k - m[i].k));
}
m[0] = {0, 0};
int ans = 0;
for(int i = 1; i <= n; i ++) {
if(m[i].h <= m[i].k - m[i - 1].k) {
ans += sum(1, m[i].h);
} else {
int temp = m[i].k - m[i - 1].k;
ans += sum(m[i - 1].h + 1, m[i - 1].h + temp);
m[i].h = m[i - 1].h + temp;
}
}
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) {
solve();
}
}
C. Not Assigning
题目概述:
构造一颗树,使得树的任意一条或两条边权之和为质数。
思路:
存在两个质数相加为质数的可以是
2
2
2 和
3
3
3 所以该题只需找到一起点,然后交替构造每条边边权为
2
,
3
2, 3
2,3即可。
如果存在度大于
3
3
3 的情况,显然是不能通过上述方式构造出树的 返回 -1
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
const int N = 1e5 + 10, M = 2 * N;
int e[M], ne[M], h[N], w[M], idx;
int d[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int fa, int flag) {
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == fa) continue;
// cout << u << ' ' << j << '\n';
if(flag == 0) {
w[i] = 2;
w[i ^ 1] = 2;
}
else {
w[i] = 3;
w[i ^ 1] = 3;
}
dfs(j, u, flag ^ 1);
}
}
void solve() {
int n;
cin >> n;
memset(h, -1, sizeof h);
memset(d, 0, sizeof d);
memset(w, 0, sizeof w);
idx = 0;
for(int i = 1; i < n; i ++) {
int u, v;
cin >> u >> v;
d[u] ++, d[v] ++;
add(u, v), add(v, u);
}
int start = 1;
for(int i = 1; i <= n; i ++) {
if(d[i] > 2) {
cout << -1 << '\n';
return;
}
if(d[i] == 1) start = i;
}
dfs(start, -1, 0);
for(int i = 0; i < 2 * n - 2; i += 2) cout << w[i] << ' ';
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t;
cin >> t;
while(t --) {
solve();
}
return 0;
}
C. Road Optimization
思路:
一道Dp 题 令
f
[
i
]
[
j
]
f[i][j]
f[i][j] 为到 第
i
i
i 个点时,已经选了
j
j
j 个速度后的时间。
状态转移:如果选择第
i
i
i 个点,则从上一个点
k
k
k 到当前点
i
i
i 增加的时间为
(
d
[
i
]
−
d
[
k
]
)
∗
a
[
k
]
(d[i] - d[k]) * a[k]
(d[i]−d[k])∗a[k]
所以状态转移方程
f
[
i
]
[
j
]
=
m
i
n
(
f
[
k
]
[
j
−
1
]
+
(
d
[
i
]
−
d
[
k
]
)
∗
a
[
k
]
)
f[i][j] = min({f[k][j - 1] + (d[i] - d[k]) * a[k]})
f[i][j]=min(f[k][j−1]+(d[i]−d[k])∗a[k])
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
void solve() {
int n, l, k;
cin >> n >> l >> k;
vector<int> a(n + 1), d(n + 1);
for(int i = 1; i <= n; i ++) cin >> d[i];
for(int i = 1; i <= n; i ++) cin >> a[i];
d[++ n] = l;
//当前第 i 个点 已经选择了 j 个速度下的时间
int f[n + 10][n + 10];
memset(f, 0x3f, sizeof f);
f[1][1] = 0;
for(int i = 2; i <= n; i ++)
for(int j = 1; j <= i; j ++)
for(int k = 1; k < i; k ++)
f[i][j] = min(f[i][j], f[k][j - 1] + (d[i] - d[k]) * a[k]);
int ans = 1e9;
for(int i = 0; i <= k; i ++) ans = min(f[n][n - i], ans);
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int t = 1;
while(t --) {
solve();
}
return 0;
}