atcoder abc 356

A subsegment reverse

题目:

代码:
 

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 2e5 + 10;

int n;
int l, r;
int a[N];

int main() {
    cin >> n >> l >> r;
    for(int i = 1; i <= n; i ++ ) a[i] = i;
    for(int i = 1; i < l; i ++ ) cout << a[i] << " ";
    for(int i = r; i >= l; i -- ) cout << a[i] << " ";
    for(int i = r + 1; i <= n; i ++ ) cout << a[i] << " ";
    return 0;
}

B Nutrients

题目:

思路:暴力枚举,枚举后作比较

代码:
 

#include <iostream>

using namespace std;

const int N = 110;

int a[N][N];
int w[N];
int n, m;

int main() {
    cin >> n >> m;
    for(int i = 1; i <= m; i ++ ) cin >> w[i];
    for(int i = 1; i <= n; i ++ ) {
        for(int j = 1; j <= m; j ++ ) {
            cin >> a[i][j];
        }
    }

    for(int i = 1; i <= m; i ++ ) {
        int cnt = 0;
        for(int j = 1; j <= n; j ++ ) {
            cnt += a[j][i];
        }
        if(cnt < w[i]) {
            cout << "No" << endl;
            return 0;
        }
    }
    cout << "Yes";
    return 0;
}

C keys

题目:
思路:注意到n很小,因此考虑状态压缩,枚举所有情况,如果符合m个条件及该情况成立,ans ++

代码:

#include <iostream>

using namespace std;

int n, m, k;
int g[110][20], re[110];

int main() {
    cin >> n >> m >> k;
    for(int i = 1; i <= m; i ++ ) {
        int x;
        cin >> x;
        while(x -- ) {
            int j;
            cin >> j;
            g[i][j] = 1;
        }
        char c;
        cin >> c;
        re[i] = c == 'o'? 1: 0;
    }

    int ans = 0;    
    for(int i = 0; i <= (1 << n) - 1; i ++ ) {
        bool ok = 1;
        for(int j = 1; j <= m; j ++ ) {
            int cnt = 0;
            for(int u = 1; u <= 15; u ++ ) {
                int x = i >> (u - 1) & 1;
                if(x && g[j][u]) cnt ++;
            }
            if(re[j]) {
                if(cnt < k) ok = 0;
            } else {
                if(cnt >= k) ok = 0;
            }
        }
        if(ok) ans ++;
    }
    cout << ans;
    return 0;
}

D masked popcount

题目:

思路:位运算,对m拆位后,对于m第i位的二进制数字x,只有x为1时对答案有贡献,于是问题变成了找到1 ~ n中所有第i位(m >> (i - 1) & 1 == 1)为1的1的总和。

由于n很大,暴力会t,因此考虑寻找某些规律

000001

000010

000011

000100

000101

000110

000111

001000

注意到从右向左第i位数字1与0会形成包含1 << i个0与1(其中01都是1 << i - 1个)的循环节,因此对每一位先计算n中包含几个循环节,再算余数(上述式子从0开始,因此n实际上是第n + 1个数)

代码:
 

#include <iostream>

using namespace std;

const int mod = 998244353;

typedef unsigned long long ULL;

int main() {
    ULL n, m;
    cin >> n >> m;
    ULL ans = 0;
    for(int i = 0; i <= 59; i ++ ) {
        ULL x = (m >> i) & 1;
        if(!x) continue;
        ULL cnt = (n + 1) / (1ULL << i + 1) * (1ULL << i);
        ULL backupn = n + 1;
        ULL reminder = (backupn % (1ULL << i + 1) > (1ULL << i))? backupn % (1ULL << i + 1) - (1ULL << i): 0;
        ans = ((ans % mod) + (cnt % mod) + (reminder % mod)) % mod;    
    }
    cout << ans;
    return 0;
}

E max/min

题目:

思路:注意到问题实际上把所有元素都做一遍比较,并且用大的数除小的数,因此最开始的思路是先sort,再用前缀和做,最后发现样例都没过去,发现前缀和会影响每个pair下去整的性质,例如3 / 2 + 3 / 2下去整 = 3 但是 s[3 + 3] / 2 = 3 并且找不到优化方法。于是注意到值域很小,考虑枚举值域,并把值域分段,x ---- 2x - 1下取整是1  2x ---- 3x - 1下取整是2 。。。。第二层循环对值域分段是一个调和级数,时间复杂度lg级别

代码:
 

#include <iostream>

using namespace std;

const int N = 1e6 + 10;

typedef long long LL;
int a[N], cnt[N];
LL s[N];

int main() {
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        cnt[a[i]] ++;
    }
    // x --- 2x - 1 --> 1; 2x --- 3x - 1 --> 2
    for(int i = 1; i <= 1000000; i ++ ) s[i] = s[i - 1] + cnt[i];
    LL ans = 0;
    for(int i = 1; i <= 1000000; i ++ ) {
        if(!cnt[i]) continue;
        for(int j = i; j <= 1000000; j += i) {
            int l = j - 1;
            int r = min(1000000, j + i - 1);
            if(j == i) l = j;
            ans += (LL)cnt[i] * (r / i) * (s[r] - s[l]);
        }
        if(cnt[i] > 1) ans += ((LL)cnt[i] * (cnt[i] - 1)) / 2;
    }
    cout << ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值