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个操作,两种:
- 询问区间l,r的近似gcd是否可以为x。
- 修改数组中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)