914 - A - Perfect Squares[模拟]
题目大意
在给出的 n n 个数中,求出不是完全平方数的最大的一个数。
思路 - 模拟
先初始化以内的完全平方数,然后遍历判断即可。
代码
#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 以及小于的所有数,最后删除所有数的人获胜。先手获胜输出: 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
的二进制下有个位为
1
1
,则将其变为。
现在给定一个二进制表示没有前导零的数
s
s
,求所有小于等于的数中,有多少数经过
k
k
次操作后会变成?
思路 - 数学
刚开始读错题了,少看个 to t o ,导致不能理解题目及样例。仔细读了好久才发现,庆幸 9 9 个月不写题还能做出三道。。。
可以想到经过一次操作后,最大只能为,所以先初始化
1000
1000
以内的数变成
1
1
所需要的操作数。
然后从高位开始枚举,设
s
s
有个二进制位,当前枚举第
l
l
位,前位共有
num
n
u
m
位为
1
1
。
①若当前位为,则令其为
0
0
时,剩余的位可以随意取值,此时再枚举这些位中恰好有
j
j
位为,若
cnt[num+j]+1==k
c
n
t
[
n
u
m
+
j
]
+
1
==
k
,则此时形成数均满足题意,计算组合数
Cjlen−l
C
l
e
n
−
l
j
即可。
②若当前位为
0
0
,则不进行计算。
注意特判和对本身的计算。
代码
#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
]
内的
gcd
g
c
d
变为
x
x
,则输出,否则输出
NO
N
O
;
②将第
j
j
个数变为。
思路 - 线段树
其实一眼就能看出来是线段树,不过比赛时想得太复杂了,不仅多考虑了 gcd g c d 为 x x 因子的情况,还少考虑了在查询时剪枝,导致复杂度一直会超。。。
看了题解后才恍然大悟,只需按照是不是
gcd
g
c
d
的因子考虑即可。
用线段树,即可在
O(logn)
O
(
l
o
g
n
)
内完成操作②,所以只需要对操作①进行分析:
a. 如果
x
x
是区间内的因子,则随意更改区间内一个数为
x
x
即可满足题意,输出。
b. 如果
x
x
不是区间内的因子,则当区间内只存在一个数不为
x
x
的倍数时,将其变为即可满足题意,输出
YES
Y
E
S
;否则无法满足题意,输出
NO
N
O
。
合并上述判断条件:当区间内不为
x
x
的倍数的数多于个时,输出
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);
}
}
}
}