刷题之Codeforces Round #757 (Div. 2)

刷题之Codeforces Round #757 (Div. 2)

[1614A]. Divan and a Store

  • 思路:存入所有可选的,从小到大选择
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 1e5 + 5;
const db eps = 1e-10;
int cas, n, l, r, k, a[N], ans, cnt;
int main(){
    cin >> cas;
    while(cas--){
        cin >> n >> l >> r >> k;
        cnt = 0;
        rep(i, 1, n){
            int x; cin >> x;
            if(l <= x && x <= r) a[++cnt] = x;
        }
        sort(a + 1, a + 1 + cnt);
        ans = 0;
        for(int i = 1; i <= cnt; i++){
            if(k < a[i]) break;
            k -= a[i];
            ans++;
        }
        cout << ans << endl;
    }
}

[1614B]. Divan and a New Project

  • 思路:不妨设 x 0 x_0 x0 在原点处。由于所有位置需要为整数,且要求距离最短,即为 ± 1 , ± 2 , . . . \pm1,\pm2,... ±1,±2,...。贪心选择,要去次数最多的放到最近,于是排序按照访问次数从大到小依次赋位置 + 1 , − 1 , + 2 , − 2 , . . . +1,-1,+2,-2,... +1,1,+2,2,... 即可。
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 2e5 + 5;
const db eps = 1e-10;
int cas, n, m;
ll ans, a[N];
struct AC{
    ll w, num;
}node[N];
bool cmp(AC a, AC b){
    return a.w > b.w;
}
int main(){
    cin >> cas;
    while(cas--){
        cin >> n;
        rep(i, 1, n){
            cin >> node[i].w;
            node[i].num = i;
        }
        sort(node + 1, node + 1 + n, cmp);
        ans = 0, a[0] = 0;
        rep(i, 1, n){
            int nowaddr = ((i % 2 == 0) ? (-1 * (i / 2)): (i / 2 + 1));
            a[node[i].num] = nowaddr;
            ans += node[i].w * abs(nowaddr);  //这里需要long long
        }
        cout << ans * 2 << endl;
        rep(i, 0, n) printf("%d ", a[i]);
        cout << endl;
    }
}

[1614C]. Divan and bitwise operations

  • 思路:拆位依次运算。

    1. 首先,若序列 { a } \{a\} {a} 中至少有一个 a i a_i ai 在某位为 1 1 1,则序列中所有数 a i a_i ai 在这一位组成的 01 01 01 序列的所有非空子集的异或和为 2 n − 1 2^{n-1} 2n1

      证明:设这一位有 a 1 1 1b 0 0 0,必有有 a + b = n a+b=n a+b=n

      由于对于一个所选子集,只有恰存在奇数个 1 1 1 时,异或和才为 1 1 1。所以对于 n n n 个元素的 2 n 2^n 2n 个子集,选择奇数个 1 1 1 的集合应为 2 n − 1 2^{n-1} 2n1 个。
      在 a 个 1 中 选 择 : C a 1 + C a 3 + C a 5 + . . . = 2 a − 1 在 b 个 0 中 选 择 : 为 2 b 总 计 有 : 2 a − 1 ∗ 2 b = 2 n − 1 \begin{aligned}在a个1中选择&:C_a^1+C_a^3+C_a^5+...=2^{a-1}\\ 在b个0中选择&:为2^b\\ 总计有&: 2^{a-1}*2^b=2^{n-1}\\ \end{aligned} a1b0:Ca1+Ca3+Ca5+...=2a1:2b:2a12b=2n1

    2. 只需要检查原序列 { a } \{a\} {a} 中每一位是否有 1 1 1。若有 1 1 1 则第 t t t 位的贡献为 2 n − 1 ∗ 2 t 2^{n-1}*2^t 2n12t。因为给的是序列区间的或运算结果,则若有 a i a_i ai 在此位为 1 1 1,其所在区间或运算在此为必为 1 1 1。只有在全部区间在此位都为 0 0 0 时才能证明 { a } \{a\} {a} 序列中每一个元素在此位均为 0 0 0

    3. 最后计算贡献之和即可。

  • 最坏复杂度 O ( 30 ∗ m log ⁡ n ) O(30*m\log n) O(30mlogn)

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
#define db double
#define VI vector<int>
#define PII pair<int, int>
const db Pi = 3.141592653589793;
const int INF = 0x7fffffff;
const int N = 2e5 + 5;
const ll mod = 1e9 + 7;
const db eps = 1e-10;
int cas, n, m, seg[N];
ll ans;
ll power(ll a, ll b, ll mod){
    ll ans = 1;
    if(mod == 1) ans = 0;
    while(b > 0){
        if(b % 2 == 1){
            ans *= a;
            ans %= mod;
        }
        a *= a;
        a %= mod;
        b >>= 1;
    }
    return ans;
}
int main(){
    cin >> cas;
    while(cas--){
        cin >> n >> m;
        rep(i, 1, m){
            int x, y;
            cin >> x >> y >> seg[i];
        }
        ans = 0;
        rep(k, 0, 30){
            int t = (1 << k), ok = 0;
            rep(i, 1, m){
                if((seg[i] & t) > 0){  //只要这一位有一个数字为 1 ,这一位所有子集异或和为 2^(onenum + zeronum - 1) 
                    ok = 1;
                    break;
                }
            }
            if(ok) (ans += (power(2ll, n - 1, mod) * t) % mod) %= mod;
        }
        cout << ans << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值