Codeforces Round #757 (Div. 2)

本文介绍了四个算法问题的解决方案,包括在预算内最大化购买物品的数量,寻找使数组乘积绝对值之和最小的排列,计算数组所有子集异或和,以及通过重新排序数组最大化GCD之和。涉及排序、位操作、动态规划等算法思想。
摘要由CSDN通过智能技术生成

A. Divan and a Store

题目概述:
K K K 元,买价值在 [ l , r ] [l,r] [l,r]之间的物品,最多买几个。

思路:
从小到大排序后挨着买就好
代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 110;
ll a[N];
ll n, l, r, k;
ll cnt;

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 --) {
        cin >> n >> l >> r >> k;
        cnt = 0;
        for(int i = 1; i <= n; i ++) cin >> a[i];
        sort(a + 1, a + n + 1);
        for(int i = 1; i <= n; i ++) {
            if(a[i] < l || a[i] > r) continue;
            k -= a[i];
            if(k < 0) break;
            cnt ++;
        }
        cout << cnt << '\n';
    }
}

B. Divan and a New Project

题目概述:
若令 x 0 = 0 x_0 = 0 x0=0 题目转化为
一个长度为 n n n 的数组 a a a ,现在要求找到一个长度为 n n n b b b 数组使得 ∑ i = 1 n ∣ a [ i ] ∗ b [ i ] ∣ \sum_{i = 1}^{n}|a[i] * b[i]| i=1na[i]b[i]最小。

思路:
a a a 排序后, 按照从大到小的顺序依次排放在 x 0 x_0 x0 的两边即可。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10;


int n;
struct Node {
    ll num, pos;

    bool operator < (const Node &W) const {
        return num > W.num;
    }
}a[N];

void solve() {
    cin >> n;
    int ans[n + 1];
    int b[n + 1];
    for(int i = 1; i <= n; i ++) {
        cin >> a[i].num;
        b[i] = a[i].num;
        a[i].pos = i;
    }
    sort(a + 1, a + n + 1);
    int x = 1;
    ans[0] = n;
    //按照(1,-1,2,-2.....) 来放
    for(int i = 1; i <= n; i ++) {
        if(i % 2) {
            ans[a[i].pos] = n + x; 
        } else {
            ans[a[i].pos] = n - x;
            x ++;
        }
    }

    ll cnt = 0;
    for(int i = 1; i <= n; i ++) {
        cnt = cnt + abs(ans[i] - n)  * b[i];
    }
    cout << cnt * 2 << '\n';
    for(int i = 0; i <= n; i ++) cout << ans[i] << ' ';
    cout << '\n';
}

signed main() {
#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. Divan and bitwise operations

题目概述:
给出数个 l , r , x l, r, x l,r,x 表示 数组 a a a a l ∣ a l + 1 . . . ∣ a r = x a_l | a_{l+1} ...|a_r = x alal+1...ar=x a a a 中的每个数都会被包括在其中,现在要求出 a a a 的所有子集的异或之和。
思路:
数组 a a a 的子集数量为 2 n 2^n 2n 个,当某个区间异或值中的某一二进制位为 1 1 1 时,则对于这个区间来说,如果一定选择该位为 1 1 1 的数,子集数量会变为 2 n − 1 2^{n-1} 2n1。 所以一定包含 2 n − 1 2^{n - 1} 2n1 个子集的异或值有该位为1的数。
综上,我们对于整个 a a a 数组来说,选择区间为整个数组,我们求得所有数的异或值 a n s ans ans, 最终的答案就是 a n s ∗ 2 n − 1 ans * 2^{n-1} ans2n1

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;

ll qmi(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

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 --) {
        int n, m;
        cin >> n >> m;
        ll x;
        ll ans = 0;
        while(m --) {
            cin >> x >> x >> x;
            ans |= x;
        }
        cout << ans * qmi(2, n - 1) % mod << '\n';
    }
}

D1. Divan and Kostomuksha (easy version)

题目概述:
通过重新排序 a a a ∑ i = 1 n g c d ( a 1 , a 2 , . . . a i ) \sum_{i=1}^ngcd(a_1,a_2,...a_i) i=1ngcd(a1,a2,...ai) 的最大值

思路:
d p [ x ] dp[x] dp[x] 表示以 g c d = x gcd = x gcd=x 开始,能得到的最大值。

  1. 要得到连续的 g c d ( ) gcd() gcd() 最大,则我们可以将 x x x 的倍数添加进这个序列中,所得到的值为 x x x
  2. 在添加完 x x x 的倍数后,添加其他数 z z z 时,此时的 g c d gcd gcd 变为了 y y y
  3. 那么 d p [ x ] = d p [ y ] + ( x − y ) ∗ c n t [ x ] dp[x] = dp[y] + (x - y) * cnt[x] dp[x]=dp[y]+(xy)cnt[x] ( c n t [ x ] cnt[x] cnt[x] 表示 d p [ x ] dp[x] dp[x] g c d = x gcd = x gcd=x 的元素数量) 这是添加完 z z z 后,使得 g c d = x gcd = x gcd=x 中的所有贡献减少了 x − y x - y xy

所以状态转移方程为: d p [ x ] = m a x ( d p [ y ] + ( x − y ) ∗ c n t [ x ] ) dp[x] = max(dp[y] + (x - y) * cnt[x]) dp[x]=maxdp[y]+(xy)cnt[x]
初始状态 d p [ 1 ] = n dp[1] = n dp[1]=n 表示 g c d = 1 gcd = 1 gcd=1 时的和
代码:

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5e6 + 10;
ll a[N], cnt[N], dp[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 n;
    cin >> n;
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        cnt[a[i]] ++;
    }

    for(int i = 1; i <= N; i ++)
        for(int j = i * 2; j <= N; j += i)
            cnt[i] += cnt[j];

    dp[1] = n; //gcd == 1时 和为 n

    for(int i = 1; i <= N; i ++) 
        for(int j = i * 2; j <= N; j += i) {
            dp[j] = max(dp[j], dp[i] + (j - i) * cnt[j]);
        }

    cout << *max_element(dp + 1, dp + 1 + N) << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值