codeforces 1000~2000

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]) (ji+h[i]) 时,这条线就需要重新画,因而后面的点会影响前面点的答案,所以我们先倒着做一次,如果出现上述情况,则直接将 h [ i ] h[i] h[i] 的高度提高到 ( h [ j ] − ( j − i ) ) (h[j] - (j - i)) (h[j](ji)),显然这样是不会影响最终答案的,然后再正着做一次。
正着做的应当是当 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][j1]+(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值