2022牛客寒假算法基础集训营5

【版权问题,不放题面了】

C.战旗小孩

思路
  • 贪心:假设我们找到了合适的k局有四个英雄选择,当一个人想上分(不摆烂)的时候,必然要抢自己最🐂的英雄,9f也不例外,每一局他都要选择他能选择的里面最厉害的那个(贡献值最高的那一个),贪心的想,为了能上线次数最多,肯定先把大的贡献放前面呀,因为如果大的放后面,可能前面就会造成漏掉某一局上榜的机会。所以贪心的安排游戏的顺序。
  • 二进制枚举(状压):如何选择合适的k个游戏使用特权呢?因为数据量很小(1<<20),所以我们可以枚举出所有合法情况,然后比较最优的合法情况。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 30;
int p[maxn];
struct Node{
    int a, b, c, d;
}node[maxn];
int f(int x){
    int res = 0;
    while(x){ x &= x - 1; res++;}
    return res;
}
int main(){
    int n, k, s; cin >> n >> k >> s;
    for(int i = 1; i <= n; i++) cin >> p[i];
    for(int i  = 1; i <= n; i++) cin >> node[i].a >> node[i].b >> node[i].c >> node[i].d;
    vector<int> useful;
    for(int i = 0; i < (1 << n); i++){
        if(f(i) == k) useful.push_back(i);
    }
    int ans = 0;
    for(auto te: useful){
        int res = 0;
        vector<int> temp;
        for(int i = 1; i <= n; i++){
            if(te & 1) temp.push_back(max(node[i].a, max(node[i].b , max(node[i].c , node[i].d))));
            else temp.push_back(max(node[i].a , node[i].b));
            te >>= 1;
        }
        sort(temp.begin(), temp.end(), greater<>());
        int value = s;
        for(int i = 1; i <= n; i++) {
            value += temp[i - 1];
            if(value >= p[i]) res++;
        }
        ans = max(ans, res);
    }
    cout << ans;
}

D. 数位小孩

思路

数位DP模板题或者常规DFS题。

因为最近学习数位DP,用数位DP写的。

dfs(int pos, int pre, int flag, int limit, int sy)

  • pos:数位坐标
  • pre:前一个数位的值
  • flag:是否都“顶边”
  • limit:用来去除前缀0
  • sy:是否存在1
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<int> nums;
bool vis[30];
ll dp[14][14][2][2];
ll dfs(int pos, int pre, int flag, int limit, bool sy){
    if(pos < 0) return !limit && sy;
    if(!flag && dp[pos][pre][limit][sy] != -1) return dp[pos][pre][limit][sy];
    int mx = 0;
    if(flag) mx = nums[pos];
    else mx = 9;
    ll res = 0;
    for(int i = 0; i <= mx; i++){
        if(i == 0 && limit)
            res += dfs(pos - 1, i, flag && i == mx, limit && i == 0, sy || i == 1);
        else if(limit || vis[i + pre])
            res += dfs(pos - 1, i, flag && i == mx, limit && i == 0, sy || i == 1);
    }
    if(!flag) dp[pos][pre][limit][sy] = res;
    return res;
}
ll work(ll x){
    nums.clear();
    while(x) nums.push_back(x % 10), x /= 10;
    return dfs((int)nums.size() - 1, 0, 1, 1, 0);
}
int main(){
    memset(dp, -1, sizeof dp);
    vis[2] = vis[3] = vis[5] = vis[7] = vis[11] = vis[13] = vis[17] = vis[19] = true;
    ll l, r; cin >> l >> r;
    cout << work(r) - work(l - 1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LOTRcsl

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

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

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

打赏作者

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

抵扣说明:

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

余额充值