Codeforces Round #765 (Div. 2)部分题解

本篇题解只是记录我的做题过程代码,不提供最优解
(另外这里所有的时间复杂度都只分析单个样例,不算 t t t的时间复杂度)

A

点击此处查看对应的题目.
本题设计算法:贪心 + 位运算
将每个数拆开为2进制,统计所有数的二进制位置1多还是0多,然后根据题意取出较多的那个为作为答案位

贪心策略:对每位考虑,如果该位1多,就设为1,反之为设为0

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int,int> PII;
const int N = 10010;
int n,l;

void split_sum(int x,int index,vector<PII> &v)
{
    while (x){
        if (x % 2) v[index].second ++;
        else v[index].first ++;
        index ++;
        x >>= 1;
    }
    
    while (index < l && !x) v[index ++].first ++; 
}
int main()
{
    int t;
    cin >> t;
    while (t -- ){
        cin >> n >> l;
        vector<PII> cnt(N,{0,0});
        vector<int> num;
        for (int i = 0;i < n;i ++ ) {
            int x;
            cin >> x;
            split_sum(x,0,cnt);
        }
        
        for (int i = 0;i < l;i ++ ){
            if (cnt[i].first >= cnt[i].second) num.push_back(0);
            else num.push_back(1);
        }
        
        int bit = 1,sum = 0;
        for (int i = 0;i < num.size();i ++) {
            sum += num[i] * bit;
            bit <<= 1;
        }
        cout << sum << '\n';
    }
    return 0;
}


B

点击此处查看对应的题目.
本题设计算法:贪心
假如我们找到了两个相同的数,设分别在 l , r l, r l,r,要求框出这段范围,那么这个范围的最大值就是 l l l 前面的数加上 r r r后面的数并加上该数,所以要让 (l - 1) + (n - r) + 1 最大,我这里通过pair存一下相同数的下标, 遍历取最大即可。

贪心策略:通过排序快速找到相同数值的下标

时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
const int N = 3e5 + 10,INF = 1e9 + 7;
typedef pair<int, int> PII;
PII a[N];
bool st[N];

int main()
{
    int t;
    cin >> t;
    while (t -- ){
        int n;
        cin >> n;
        for (int i = 1;i <= n;i ++ ) {
            cin >> a[i].first;
            a[i].second = i;
        }

        sort(a + 1,a + n + 1);

        int maxn = -INF;
        for (int i = 1;i < n;i ++ ) {
            if (a[i].first == a[i + 1].first ) {
                int x = (a[i].second - 1) + (n - a[i + 1].second) + 1;
                maxn = max(maxn , x);
            }
        }

        if (maxn == -INF) puts("-1");
        else cout << maxn << '\n';
    }
    return 0;
}


C

点击此处查看对应的题目.
本题设计算法:动态规划
状态表示: d p [ i ] [ j ] dp[i][j] dp[i][j] 表示以第 i 个标识牌为结尾且拆了 j 个限速牌花费的最少时间,其中 第一个标识牌不拆。

状态转移: d p [ i ] [ j ] = m i n p r e = 0 j ( d p [ i ] [ j ] , d p [ i − p r e − 1 ] [ j − p r e ] + ( s [ i ] − s [ i − p r e − 1 ] ) ∗ f r a v [ i − p r e − 1 ] ) dp[i][j]=min^j_{pre = 0}(dp[i][j],dp[i - pre - 1][j - pre] + (s[i] - s[i - pre - 1]) * frav[i - pre - 1]) dp[i][j]=minpre=0j(dp[i][j],dp[ipre1][jpre]+(s[i]s[ipre1])frav[ipre1]) ————其中frav表示速度的倒数,pre是前面的可保留的标识牌

状态转移也可以用状态划分来表示:
请添加图片描述

转化为01背包问题就好理解了(本质上都是有代价的最优组合问题)

时间复杂度 O ( n 3 ) O(n^3) O(n3)

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1010,INF = 0x3f3f3f3f;
int s[N],fra_v[N],dp[N][N];
int n,l,k;

int main()
{
    cin >> n >> l >> k;
    for (int i = 1;i <= n;i ++ ) cin >> s[i];
    for (int i = 1;i <= n;i ++ ) cin >> fra_v[i];

    s[n + 1] = l;
    memset(dp,0x3f,sizeof dp);
    dp[1][0] = 0;
    for (int i = 2;i <= n + 1;i ++){
        for (int j = 0;j <= k;j ++ ) {
            dp[i][j] = dp[i - 1][j] + (s[i] - s[i - 1]) * fra_v[i - 1];//先把之前的状态继承过来
            //必然拔掉一个,所以从1枚举
            for (int pre = 1;pre <= j;pre ++ ) {
                if (i - pre - 1 <= 0) break;
                dp[i][j] = min(dp[i][j],dp[i - pre - 1][j - pre] + (s[i] - s[i - pre - 1]) * fra_v[i - pre - 1]);
            }
        }
    }

    int res = INF;
    for (int i = 0;i <= k;i ++ ) res = min(res,dp[n + 1][i]);
    cout << res << '\n';

    return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

marvel121

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值