DP训练(codeforces)

第一题 D - Earn or Unlock

问题简述

  • n卡牌从上往下放,开局有一次操作次数。(操作类型如下):
  • 1.将卡牌的值转化为操作次数
  • 2.获取卡牌的值
  • 问最多能获取卡牌的值。

思路

  • dp背包

    我们可以清楚的知道取了前i个卡牌时获得的所有卡牌的值,并且知道一定消耗了i - 1次操作 所以当取了前面i个时消耗了i - 1次操作机会,获得了前i个卡牌的值之和减(i - 1) 所以直接用背包确定在前i个时是否能精准取到(为什么是精准呢,因为可以贪心的认为取的越多越好)

  • 但是单纯的用背包是不可以应用在当前的1e5的复杂度上的,所以可以用二进制bitset来优化背包的复杂度

代码

ini 复制代码
**include <bits/stdc++.h> 
using namespace std;
#define int long long
const int N = 3e5 + 5;
const int mod = 1e9 + 7;


int a[N];
bitset<N>dp;
void solve() {
    int n;
    int sum = 0;
    int ans = 0;
    
    cin >> n;    
    for(int i = 0;i < n;i++) {
        cin >> a[i];
    }
    n *= 2;//其实是n + n

    dp[0] = 1; // 初始化dp
    for(int i = 0;i < n;i++) {
        dp |= (dp << a[i]); // 二进制背包 ,优化复杂度 ,取第i个值用作操作一
        sum += a[i];//前缀
        if(dp[i] == 1) {//当背包刚好能取i时,有i的值被转化为了
            ans = max(ans , sum - i);   
            dp[i] = 0;//同时因为是刚好取到i,所以当不取时结束
        }
    }
    cout << ans << "\n";


}

signed main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 
    int _ = 1;
    // cin>>_;
    while(_--)
    {
        solve();
    } 
}

第二题 F - Divide, XOR, and Conquer

问题简述

给定n个数ai,ai<=2^60

将这n个数进行以下操作。

选择第k个位置1<=k<n,令x=a1^a2^...^ak,y=ak+1^ak+2^...^an

  • 如果x>y,保留a1,a2,...,ak
  • 如果x<y,保留ak+1,ak+2,...,an
  • 如果x==y,保留前面或者后边都可。

问,对于1<=i<=n,能否通过上述操作,保留剩下第i个元素。、

思路

已知对于一段区间异或l ,r ,令s为此区间的异或和,则有以下两种情况: 令k , x , y如问题简述所述

1.s = 0 则x == y , 任意x 或 y区间都可以删 2.s != 0 ,则存在x (或y) 的最高位与区间的异或和最高位相同时x > y(y > x)

(请读者细品为什么)

然后就是直接枚举长度从大到小,定义两个数组sti为以i为左边界的区间最高位的集合,ed为右区间 (区间dp)

代码

ini 复制代码
#include <bits/stdc++.h> 
using namespace std;
#define int long long
const int N = 3e5 + 5;
const int mod = 1e9 + 7;
const int M = ((int)1 << 61) - 1;

int a[N];

int hb(int x) {//获取最高位的值15 -> 8
    if(!x) return M;
    else {
        return (int)1 << (63 - __builtin_clzll(x));
    }
}

void solve() {
    int n ;
    cin >> n;
    vector<int>s(n + 1);//前缀和
    for(int i = 1;i <= n;i++) cin >> a[i] , s[i] =(s[i - 1] ^ a[i]);

    if(n == 1) {cout << 1 << "\n";return;}
    
    
    vector<int>st(n + 1) , ed(n + 1);
    st[1] = ed[n] = hb(s[n]); //初始化
    
    for(int len = n;len >= 1;len--) {
        for(int l = 1;l + len - 1 <= n;l++) {
            int r = l + len - 1;
            int sum = (s[r] ^ s[l  - 1]);//区间异或和

            int msk = (sum & st[l]) | (sum & ed[r]);
            //记录区间是否合法,用之前说的方法
            //如果以l为左边界或以r为右边界且包含了该区间的大区间存在最高位与sum且了那么该区间合法
            //说明该区间可以被这个 最高位且sum 的大区间给用操作减去一个小区间获取
            int flag = 0;
            if(msk or st[l] == M or ed[r] == M) {
                st[l] |= hb(sum) , ed[r] |= hb(sum);//更新l , r的最高位集合
                flag = 1;
            }
            if(len == 1) cout << flag;
        }
    }
    cout << "\n";
}

signed main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
 
    int _ = 1;
    cin>>_;
    while(_--)
    {
        solve();
    } 
}
相关推荐
依然鸣1 小时前
PTA团体程序设计天梯赛L2真题讲解L2-001-004
经验分享·学习·算法·深度优先·pat考试
杨航 AI2 小时前
** AI 面试算法 50 题清单**,不是单纯的 LeetCode 题号列表,而是按照“**考察概率 × 面试价值 × 你当前准备方向**”排序
算法·leetcode·面试
m0_720245019 小时前
1543.统计好三元组(简单)
开发语言·算法
To_OC9 小时前
LC 560 和为 K 的子数组:前缀和配哈希表,这对组合我是真的服了
javascript·算法·程序员
hans汉斯10 小时前
《软件工程与应用》期刊推荐&10月版面征稿中
图像处理·人工智能·深度学习·算法·音视频·软件工程
叠层归一研究院10 小时前
AGI 系统(八):符号范畴嵌入函子 — SymCat ↪ C_M107 严格化
c语言·开发语言·人工智能·算法·transformer·agi
其美杰布-富贵-李11 小时前
08 进阶评估指标与算法特定指标
人工智能·算法
.道阻且长.12 小时前
5.LeetCode算法习题讲解--双指针--有效三角形的个数
算法·leetcode·职场和发展
我是海飞12 小时前
杰理JL703N SSD1306 OLED(128x64) 点阵屏移植说明
单片机·算法·嵌入式·音频·杰理
wabs66613 小时前
关于图论【最短路径之Bellman_ford 算法(单源有限最短路)|卡码网96.城市间货物运输III的思考】
数据结构·算法·图论·卡码网·bellman_ford·单源有限最短路