Codecraft-18 and Codeforces Round #458 (Div. 1 + Div. 2, combined)

20 篇文章 0 订阅
20 篇文章 0 订阅

比赛链接

qaq这场比赛rating暴涨(小号)

A. Perfect Squares

题意:

求最大的不是完全平方数的数。

做法:

直接从大到小排序即可。

有一个很有趣的东西。。
就是这道题是有负数的,按理来讲是要判一下的因为负数没法sqrt。
但是我没判也可以过。。。
我后来发现cf的评测机好像sqrt一个负数会返回-2147483647,然后-2147483647的平方就爆long long了应该也会返回一个-2147483647或者其它奇奇怪怪的负数,总之不会=原来的负数,所以我那个直接判断也是可以过的qaq。。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int N = 1010;
int n;
int a[N];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    sort(a+1, a+1+n);
    for(int i = n; i >= 1; i --) {
        int x = sqrt(a[i]);
        if(x*x != a[i]) {
            printf("%d\n", a[i]);
            return 0;
        }
    }
}

B. Conan and Agasa play a Card Game

题意:

两个人A,B玩游戏。
有n张卡牌,每张牌上写了数字。A先手。每次可以取一张牌,然后可以拿走所有数字严格比它小的牌。
最后拿走所有牌的人胜。问最后谁会胜。

做法:

简单博弈。
发现只要有一种(或多种)数字的个数时奇数就是先手赢,否则后手赢。
因为假如有奇数,就在所有数字个数为奇数的牌里最大的那个数字取一张牌。
然后接下来都是偶数了,对方取一张你也取相同数字的一张,对称地取。然后你就赢了。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;

const int N = 100010;
int n;
int tong[N];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) {
        int x; scanf("%d", &x); tong[x] ++;
    } bool flag = 0;
    for(int i = 1; i <= 100000; i ++)
        if(tong[i]) flag |= tong[i]&1;
    if(flag) puts("Conan"); else puts("Agasa");
    return 0;
}

C. Travelling Salesman and Special Numbers

题意:

定义一个二进制数经过一次操作可以变成它二进制1的个数。
现在给一个n(二进制)和k,问能用k次变成1的不超过n的二进制数的个数。

做法:

显然数位dp。
先预处理一个g[i]表示有二进制中i个1,变成1的操作数。
然后直接上数位DP即可。
注意k=0和k=1的特判。
(k=1特判一开始没加,后来重交了一发排名降了很多啊心疼)

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;

const int N = 1010;
const int inf = 1e9;
const int mod = 1e9 + 7;
int k;
char s[N];
int f[N][N], g[N], vis[N][N];

inline int dfs(int len, int x, bool flag) {
    if(!s[len]) {
        if(g[x]+1 == k) return 1; else return 0;
    }
    if(!flag && f[len][x] != -1) return f[len][x];
    int ret = 0, ed = flag?(s[len]-'0'):1;
    for(int i = 0; i <= ed; i ++) ret = (ret+dfs(len+1, x+i, flag&(i == ed)))%mod;
    if(!flag) f[len][x] = ret;
    return ret;
}
int main() {
    scanf("%s%d", s+1, &k); int len = strlen(s+1);
    if(!k) { puts("1"); return 0; }
    g[0] = inf;
    for(int i = 2; i <= len; i ++) {
        int x = 0;
        for(int j = i; j; j -= j&-j) x ++;
        g[i] = g[x]+1;
    }
    memset(f, -1, sizeof f);
    printf("%d\n", k == 1 ? dfs(1, 0, 1)-1 : dfs(1, 0, 1));
    return 0;
}

D. Bash and a Tough Math Puzzle

题意:

给n个数。
定义一个区间的近似gcd为,可以任意去掉一个数,剩下的数的gcd。
现在有q个操作,两种:

  1. 询问区间l,r的近似gcd是否可以为x。
  2. 修改数组中x位置的值为y。

做法:

首先线段树维护一个区间gcd。
然后由于从一个数开始向左(向右)的gcd肯定是单调不增,满足单调性,所以对于每一个[l,r],找到最右边的x满足[l,t1]的gcd是x的倍数,以及最左边的y满足[y,r]的gcd是x的倍数。
然后检验一下x,y之间是否相差小于等于1个数字即可。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<cmath>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
    char ch = getchar(); ll x = 0; int op = 1;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
    for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
    return x*op;
}
inline void write(ll a) {
    if(a < 0) putchar('-'), a = -a;
    if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 500010;
int n, m;
int a[N], g[N<<2];

inline int gcd(int a, int b) { return (!b)?a:gcd(b, a%b); }
inline void build(int o, int l, int r) {
    if(l == r) { g[o] = a[l]; return; }
    int mid = l+r>>1;
    build(lc, l, mid); build(rc, mid+1, r);
    g[o] = gcd(g[lc], g[rc]);
}
inline void update(int o, int l, int r, int x, int y) {
    if(l == r) { g[o] = y; return; }
    int mid = l+r>>1;
    if(x <= mid) update(lc, l, mid, x, y);
    else update(rc, mid+1, r, x, y);
    g[o] = gcd(g[lc], g[rc]);
}
inline int get1(int o, int l, int r, int x, int y) {//最右边使得gcd(x..i)=z的位置
    if(g[o]%y == 0) return r; if(l == r) return l-1;
    int mid = l+r>>1;
    if(x <= mid) {
        int tmp = get1(lc, l, mid, x, y);
        if(tmp == mid) tmp = get1(rc, mid+1, r, x, y);
        return tmp;
    } else return get1(rc, mid+1, r, x, y);
}
inline int get2(int o, int l, int r, int x, int y) {
    if(g[o]%y == 0) return l; if(l == r) return r+1;
    int mid = l+r>>1;
    if(x > mid) {
        int tmp = get2(rc, mid+1, r, x, y);
        if(tmp == mid+1) tmp = get2(lc, l, mid, x, y);
        return tmp;
    } else return get2(lc, l, mid, x, y);
}
int main() {
    n = read();
    for(int i = 1; i <= n; i ++) a[i] = read();
    build(1, 1, n);
    m = read();
    while(m --) {
        int opt = read(), x = read(), y = read(), z;
        if(opt == 1) {
            z = read(); int l = get1(1, 1, n, x, z), r = get2(1, 1, n, y, z);
            if(l+2 >= r) puts("YES"); else puts("NO");
        } else update(1, 1, n, x, y);
    }
    return 0;
}

总结:

小号打的
比赛时通过ABCD,rank 216,rating +188.
感觉E和G好像还可做?(没看过题目但是看ac人数这么感觉)
如果有空做了话再来补题解。
(争取小号快点升紫啊)
(话说下次好像有一场div1了啊大号可能要掉分了啊好慌)
(那可是我第一场div1?qwq)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值