小白月月赛48
写在前面:感觉实习之后好久好久没有更新blog了,昨天人生中第一次找女孩子搭讪要到了微信,到现在都感觉有点心跳过快(怂比本比了)。恭亲王府之行也因为一大早的突击核酸又搁置了,今天不想看论文趁闲打了场重现赛,除了手速不如以前了感觉一切还是在本科实验室时的情形,还是蛮开心的。
比赛网址
A. 孤独的数组
思路: Ai-1和Ai暴力求gcd即可,如存在gcd不为1,输出-1,否则输出0。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f, x) memset(f, x, sizeof(f))
using namespace std;
const int M = 1e4 + 50;
const int N = 1e5 + 50;
int n;
int gcd(int x, int y){
return y == 0 ? x : gcd(y, x%y);
}
int main(){
int cur, next;
cin >> n;
cin >> cur;
int ans = 0;
for(int i = 1; i < n; i++){
cin >> next;
if(gcd(cur, next) != 1){
ans = -1;
}
cur = next;
}
printf("%d\n", ans);
return 0;
}
B. 博弈大师
思路: 很容易想到,谁的技能卡多,谁就能赢(如果最终处于必输态,只要用技能卡转换操作者,将输态转移给对方即可,对方使用技能卡转移状态时,我方也可使用技能卡抵消),当两方技能卡数量相同时,相当于谁都没有卡,看常规轮流操作操作的输赢即可,这个操作轮数可以用二分求解。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f, x) memset(f, x, sizeof(f))
using namespace std;
const int M = 1e4 + 50;
const int N = 1e5 + 50;
ll BiSearch(ll x){
ll L = 0, R = 1e9;
ll mid;
while(L <= R){
mid = (L+R)>>1;
ll tmp = (mid+1)*mid/2;
if(tmp == x) return mid+1;
if(tmp > x)
R = mid-1;
else
L = mid+1;
}
return L;
}
int main(){
int t;
cin >> t;
while(t--){
ll n, a, b;
cin >> n >> a >> b;
if(a > b) cout << "niuniu\n";
if(a < b) cout << "niumei\n";
if(a == b){
ll res = BiSearch(n);
if(res&1) cout << "niuniu\n";
else cout << "niumei\n";
}
}
return 0;
}
C. 可疑的区间
思路: 先考虑求有趣值,就是求我们设定的长度为len的区间和这n个有趣区间中有交集的个数。很典型的线段树或者树状数组,这里直接求是否有交集情况比较复杂,可以考虑容斥:n - 没有交集的区间数。没有交集的区间有两种情况:
- 有趣区间的右端点在设定区间的左端点左侧
- 有趣区间的左端点在设定区间的右端点右侧
我们只需要分别维护有趣区间左右端点的树状数组即可,同理求权重也只需要维护两个树状数组即可。一共4个树状数组,时间复杂度nlogn。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f, x) memset(f, x, sizeof(f))
using namespace std;
const int M = 1e7 + 50;
const int N = 1e7 + 50;
int m, n;
ll Lsum[N], Rsum[N];
int Lcnt[N], Rcnt[N];
void init(){
mem(Lsum, 0);
mem(Rsum, 0);
mem(Lcnt, 0);
mem(Rcnt, 0);
}
int lowbit(int x){
return x&-x;
}
void update_Lsum(int x, int w){
while(x < N){
Lsum[x] += w;
x += lowbit(x);
}
}
void update_Rsum(int x, int w){
while(x < N){
Rsum[x] += w;
x += lowbit(x);
}
}
void update_Lcnt(int x){
while(x < N){
Lcnt[x] += 1;
x += lowbit(x);
}
}
void update_Rcnt(int x){
while(x < N){
Rcnt[x] += 1;
x += lowbit(x);
}
}
ll get_Lsum(int x){
ll res = 0;
while(x > 0){
res += Lsum[x];
x -= lowbit(x);
}
return res;
}
ll get_Rsum(int x){
ll res = 0;
while(x > 0){
res += Rsum[x];
x -= lowbit(x);
}
return res;
}
int get_Lcnt(int x){
int res = 0;
while(x > 0){
res += Lcnt[x];
x -= lowbit(x);
}
return res;
}
int get_Rcnt(int x){
int res = 0;
while(x > 0){
res += Rcnt[x];
x -= lowbit(x);
}
return res;
}
int get_interest(int L, int R){
return get_Lcnt(R)-get_Rcnt(L);
}
ll get_weight(int L, int R){
return get_Lsum(R)-get_Rsum(L);
}
int main(){
cin >> n >> m;
init();
int x, y;
int p_min = 5e6 + 50, p_max = 1;
for(int i = 1; i <= n; i++){
cin >> x >> y;
update_Lsum(x, i);
update_Rsum(y, i);
update_Lcnt(x);
update_Rcnt(y);
p_min = min(min(p_min, x), y);
p_max = max(max(p_max, x), y);
}
int ans = 0;
int max_interest = 0;
ll max_w = 0;
for(int i = max(1, p_min-m+1); i <= p_max; i++){
int L = i, R = i+m-1;
int interest = get_interest(L-1, R);
if(max_interest < interest){
max_interest = interest;
max_w = get_weight(L-1, R);
ans = 1;
}
else if(max_interest == interest){
ll weight = get_weight(L-1, R);
if(max_w < weight){
max_w = weight;
ans = 1;
}
else if(max_w == weight){
ans++;
}
}
}
cout << ans << "\n";
return 0;
}
D. 交替加乘
思路: 很容易想的贪心,排序后前半部分用做加法,后半部分用作乘法。考虑加法内部顺序,先加大的能乘更多次,肯定会比较大;考虑乘法内部顺序,后乘大的,后面大的乘的做了更多的加法,基数更大,肯定结果也会更大。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f, x) memset(f, x, sizeof(f))
using namespace std;
const int M = 1e5 + 50;
const int N = 1e5 + 50;
const int MOD = 1e9 + 7;
int m, n;
int a[N];
int main(){
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", a+i);
sort(a, a+n);
a[n] = 1;
int mid = n/2;
ll res = a[mid];
for(int i = mid-1, j = mid+1; i >= 0; i--, j++){
res = res+a[i];
res = (res*a[j])%MOD;
}
printf("%lld\n", res);
return 0;
}
E. 或与异或
思路: 没啥好讲的,倒水问题dfs或者bfs搜索的裸题。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f, x) memset(f, x, sizeof(f))
using namespace std;
const int M = 1e5 + 50;
const int N = 1e5 + 50;
const int MOD = 1e9 + 7;
ll a, b, target;
bool ans = 0;
map<pair<ll, ll>, bool> mp;
void dfs(ll x, ll y){
if(x == target || y == target){
ans = 1;
return;
}
if(!ans){
if(!mp.count({x|y, y}) && !mp.count({y, x|y})){
mp[{x|y, y}] = mp[{y, x|y}] = 1;
dfs(x|y, y);
}
if(!mp.count({x, x|y}) && !mp.count({x|y, x})){
mp[{x, x|y}] = mp[{x|y, x}] = 1;
dfs(x, x|y);
}
if(!mp.count({x&y, y}) && !mp.count({y, x&y})){
mp[{x&y, y}] = mp[{y, x&y}] = 1;
dfs(x&y, y);
}
if(!mp.count({x, x&y}) && !mp.count({x&y, x})){
mp[{x, x&y}] = mp[{x&y, x}] = 1;
dfs(x, x&y);
}
if(!mp.count({x^y, y}) && !mp.count({y, x^y})){
mp[{x^y, y}] = mp[{y, x^y}] = 1;
dfs(x^y, y);
}
if(!mp.count({x, x^y}) && !mp.count({x^y, x})){
mp[{x, x^y}] = mp[{x^y, x}] = 1;
dfs(x, x^y);
}
}
}
int main(){
int t;
scanf("%d", &t);
while(t--){
mp.clear();
scanf("%lld %lld %lld", &a, &b, &target);
mp[{a, b}] = mp[{b, a}] = 1;
ans = 0;
dfs(a, b);
if(ans)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
F. 孤独的树
思路: 简单的树形dp,从叶子节点往根节点搜,统计gcd的质因子个数。
代码:
#include <bits/stdc++.h>
#define ll long long
#define mem(f, x) memset(f, x, sizeof(f))
using namespace std;
const int M = 1e3 + 50;
const int N = 1e5 + 50;
const int MOD = 1e9 + 7;
int n;
int val[N];
int head[N], cnt;
bool vis[M];
int su[M], ct;
ll ans = 0;
struct edge{
int to;
int next;
edge():to(0), next(0){}
edge(int tt, int nn):to(tt), next(nn){}
}e[2*N];
void init(){
for(int i = 0; i <= n; i++)
val[i] = head[i] = 0;
cnt = ct = 0;
mem(vis, 1);
vis[0] = vis[1] = 0;
for(int i = 2; i < M; i++){
if(vis[i]){
su[ct++] = i;
for(int j = i*i; j < M; j += i)
vis[j] = 0;
}
}
ans = 0;
}
int gcd(int x, int y){
return y == 0 ? x : gcd(y, x%y);
}
void add(int x, int y){
e[++cnt] = edge(y, head[x]);
head[x] = cnt;
}
int get_op_num(int x){
int res = 0;
int up = sqrt(x);
for(int i = 0; su[i] <= up; i++){
while(x%su[i] == 0){
x /= su[i];
res++;
}
}
if(x > 1) res++;
return res;
}
void dfs(int x, int pre){
for(int i = head[x]; i; i = e[i].next){
int to = e[i].to;
if(to == pre) continue;
dfs(to, x);
int tmp = gcd(val[x], val[to]);
val[x] /= tmp;
ans += get_op_num(tmp);
}
}
int main(){
scanf("%d", &n);
init();
for(int i = 1; i <= n; i++)
scanf("%d", val+i);
int x, y;
for(int i = 1; i < n; i++){
scanf("%d %d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, 0);
printf("%lld\n", ans);
return 0;
}