Codeforces Round-#458 (Div. 2 && Div. 1) [Codeforces914]

24 篇文章 0 订阅
8 篇文章 0 订阅

题目链接
官方题解

914 - A - Perfect Squares[模拟]

题目大意

在给出的 n n 个数中,求出不是完全平方数的最大的一个数。

思路 - 模拟

先初始化106以内的完全平方数,然后遍历判断即可。

代码

#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>

using namespace std;

map<int, bool> square;
int n, num, ans;

int main() {
    square.clear();
    for(int i = 0; i <= 1000; ++i) {
        square[i * i] = true;
    }
    while(1 == scanf("%d", &n)) {
        ans = -10000000;
        while(n-- > 0) {
            scanf("%d", &num);
            if(!square[num]) {
                ans = max(ans, num);
            }
        }
        printf("%d\n", ans);
    }
}

914 - B - Conan and Agasa play a Card Game[贪心]

题目大意

n n 个整数,两个人轮流挑选一个数x,然后删除这一个数 x x 以及小于x的所有数,最后删除所有数的人获胜。先手获胜输出: Conan C o n a n ,后手获胜输出: Agasa A g a s a

思路 - 贪心

先手考虑选最大的数 max m a x ,如果 max m a x 出现了奇数次,则选完后,剩下偶数个 max m a x ,先手必胜。
max m a x 出现了偶数次,则先手不能选 max m a x ,否则必败;此时,先后想要获胜必定让后手第一次选 max m a x ,则先手需要在剩余的数中最后一个删除所有的数,转换成了子游戏。
以此类推:如果存在 num n u m 出现的次数为奇数,则先手选择最大的 num n u m 就能必胜。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 100003;

int n, a, cnt[MAXN];
bool conan;

int main() {
    while(1 == scanf("%d", &n)) {
        memset(cnt, 0, sizeof(cnt));
        conan = false;
        for(int i = 0; i < n; ++i) {
            scanf("%d", &a);
            ++cnt[a];
        }
        for(int i = 1; i < MAXN; ++i) {
            if((cnt[i] & 1) == 1) {
                conan = true;
            }
        }
        printf("%s\n", conan ? "Conan" : "Agasa");
    }
}

914 - C - Travelling Salesman and Special Numbers[数学]

题目大意

有一种操作:一个整数 x x 的二进制下有y个位为 1 1 ,则将其变为y
现在给定一个二进制表示没有前导零的数 s s ,求所有小于等于x的数中,有多少数经过 k k 次操作后会变成1

思路 - 数学

刚开始读错题了,少看个 to t o ,导致不能理解题目及样例。仔细读了好久才发现,庆幸 9 9 个月不写题还能做出三道。。。

可以想到经过一次操作后,最大只能为1000,所以先初始化 1000 1000 以内的数变成 1 1 所需要的操作数cnt
然后从高位开始枚举,设 s s len个二进制位,当前枚举第 l l 位,前l1位共有 num n u m 位为 1 1
①若当前位为1,则令其为 0 0 时,剩余的lenl位可以随意取值,此时再枚举这些位中恰好有 j j 位为1,若 cnt[num+j]+1==k c n t [ n u m + j ] + 1 == k ,则此时形成数均满足题意,计算组合数 Cjlenl C l e n − l j 即可。
②若当前位为 0 0 ,则不进行计算。
注意特判和对s本身的计算。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 1003;
const int MOD = 1e9 + 7;

int k, cnt[MAXN], len, ans;
int C[MAXN][MAXN];
char s[MAXN];

inline int getCntOfOneBit(int num) {
    int res = 0;
    while(num > 0) {
        num = num & (num - 1);
        ++res;
    }
    return res;
}

void init() {
    cnt[0] = -MAXN;
    cnt[1] = 0;
    for(int i = 2; i < MAXN; ++i) {
        cnt[i] = cnt[getCntOfOneBit(i)] + 1;
    }

    memset(C, 0, sizeof(C));
    C[0][0] = 1;
    for(int i = 1; i < MAXN; ++i) {
        C[i][0] = C[i][i] = 1;
        for(int j = 1; j < i; ++j) {
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
        }
    }
}

int main() {
    init();
    while(2 == scanf("%s%d", s, &k)) {
        ans = 0;
        len = strlen(s);
        if(k == 0) {
            printf("1\n");
            continue;
        }
        if(k == 1) {
            printf("%d\n", len - 1);
            continue;
        }
        int num = 0;
        for(int i = 0; i < len; ++i) {
            if(s[i] == '1') {
                for(int j = len - i - 1; j >= 0; --j) {
                    if(cnt[num + j] + 1 == k) {
                        ans = (ans + C[len - i - 1][j]) % MOD;
                    }
                }
                ++num;
            }
        }
        if(cnt[num] + 1 == k) {
            ans = (ans + 1) % MOD;
        }
        printf("%d\n", ans);
    }
}

914 - D - Bash and a Tough Math Puzzle

题目大意

有一个长为 n n 的数组,有两个操作:
①如果暂时至多改变[l,r]内的一个数后,能使 [l,r] [ l , r ] 内的 gcd g c d 变为 x x ,则输出YES,否则输出 NO N O ;
②将第 j j 个数变为y

思路 - 线段树

其实一眼就能看出来是线段树,不过比赛时想得太复杂了,不仅多考虑了 gcd g c d x x 因子的情况,还少考虑了在查询时剪枝,导致复杂度一直会超。。。

看了题解后才恍然大悟,只需按照x是不是 gcd g c d 的因子考虑即可。
用线段树,即可在 O(logn) O ( l o g n ) 内完成操作②,所以只需要对操作①进行分析:
a. 如果 x x 是区间内gcd的因子,则随意更改区间内一个数为 x x 即可满足题意,输出YES
b. 如果 x x 不是区间内gcd的因子,则当区间内只存在一个数不为 x x 的倍数时,将其变为x即可满足题意,输出 YES Y E S ;否则无法满足题意,输出 NO N O
合并上述判断条件:当区间内不为 x x 的倍数的数多于1个时,输出 NO N O ,否则输出 YES Y E S

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

#define lson (i << 1)
#define rson ((i << 1) | 1)

using namespace std;

const int MAXN = 500003;

struct Node {
    int l, r;
    int gcd;
}tr[MAXN << 2];

int L, R, X, cnt;

void build(int i, int l, int r) {
    tr[i].l = l;
    tr[i].r = r;
    if(l == r) {
        scanf("%d", &tr[i].gcd);
        return ;
    }
    int mid = (l + r) >> 1;
    build(lson, l, mid);
    build(rson, mid + 1, r);
    tr[i].gcd = __gcd(tr[lson].gcd, tr[rson].gcd);
}

void update(int i) {
    if(tr[i].l == L && tr[i].r == L) {
        tr[i].gcd = X;
        return ;
    }

    if(tr[lson].r >= L) {
        update(lson);
    }
    else {
        update(rson);
    }
    tr[i].gcd = __gcd(tr[lson].gcd, tr[rson].gcd);
}

void query(int i) {
    if(tr[i].l == tr[i].r) {
        if(tr[i].gcd % X != 0) {
            ++cnt;
        }
        return ;
    }
    if(L <= tr[i].l && tr[i].r <= R) {
        if(tr[i].gcd % X != 0) {
            if(tr[i].l == tr[i].r) {
                ++cnt;
                return ;
            }
            query(lson);
            if(cnt <= 1) {
                query(rson);
            }
        }

        return;
    }

    if(L <= tr[lson].r) {
        query(lson);
    }
    if(cnt <= 1 && R >= tr[rson].l) {
        query(rson);
    }
}

int n, q, type;

int main() {
    while(1 == scanf("%d", &n)) {
        build(1, 1, n);
        scanf("%d", &q);
        while(q-- > 0) {
            scanf("%d", &type);
            if(type == 1) {
                scanf("%d%d%d", &L, &R, &X);
                cnt = 0;
                query(1);
                printf("%s\n", cnt <= 1 ? "YES" : "NO");
            }
            else {
                scanf("%d%d", &L, &X);
                update(1);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值