A. GCD vs LCM
Sample input
5
4
7
8
9
10
Sample output
1 1 1 1
2 2 2 1
2 2 2 2
2 4 2 1
3 5 1 1
题意:
给你一个n,让你构造出四个数a,b,c,d,其中a + b + c + d = n,而且gcd(a,b) = lcm(c,d)
思路:
直接a = n-3,b,c,d = 1就行,下面看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
void solve(){
int n;
scanf("%d",&n);
printf("%d 1 1 1\n",n-3);
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
B. Array Cloning Technique
Sample input
6
1
1789
6
0 1 3 3 7 0
2
-1000000000 1000000000
4
4 3 2 1
5
2 5 7 6 3
7
1 1 1 1 1 1 1
Sample output
0
6
2
5
7
0
题意:
对于一个数组,你可以进行一次操作将这个数组copy一份,也可以进行一次操作从两个数组中选择两个位置进行交换,问你最少需要多少次操作能将这个数组中的所有元素变成一样的值
思路:
首先统计出现最多的数的次数是多少,然后可以遵循一种操作顺序,一定是最优的,就是先copy再交换,假如说一开始最多的数出现的次数是三次的话,那么先copy再交换后的最多的数出现的次数就是6次了,只进行了4次操作,然后会发现每次这种操作都是2的幂次*3,就二分一下就行,下面看代码吧
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int n,a[N];
void solve(){
int n;
int mx = 0;
scanf("%d",&n);
map<int,int> mp;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
mp[a[i]]++;
mx = max(mx,mp[a[i]]);
}
int l = 0,r = 31,ans = -1;
while(l <= r){
int mid = l + r >> 1;
if(mx*(1ll<<mid) >= n) ans = mid,r = mid - 1;
else l = mid + 1;
}
printf("%d\n",ans+n-mx);
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
C. Tree Infection
Sample input
5
7
1 1 1 2 2 4
5
5 5 1 4
2
1
3
3 1
6
1 1 1 1 1
Sample output
4
4
2
3
4
题意:
一棵树。每秒钟每个有儿子节点感染的节点i,可以感染节点i的一个其他健康儿子节点,同时可以指定一个健康节点感染。问最少多少时间,全部节点感染?
思路:
先预处理出来有多少个连通块,这个连通块意思就是说全都是兄弟节点的块,然后先按照大小次序从大到小染一遍,然后就优先队列染就行,因为目的就是尽可能的让它自己扩散,不是自己染,看代码吧:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int cnt[N],n;
void solve(){
scanf("%d",&n);
for(int i=1;i<=n;i++) cnt[i] = 0;
int len = 1;
for(int i=1;i<n;i++){
int t;
scanf("%d",&t);
cnt[t]++;
len += cnt[t] == 1;
}
sort(cnt+1,cnt+1+n);
priority_queue<int> q;
int tim = len;
for(int i=n;i>=1;i--)
if(!cnt[i]){
cnt[i]++;
break;
}
for(int i=n;i>=1;i--){
if(cnt[i]){
if(cnt[i] > len) q.push(cnt[i]-len);
len --;
}
}
len = 1;
while(!q.empty()){
int t = q.top();
q.pop();
if(t < len) continue;
len ++;
tim ++;
q.push(t - 1);
}
printf("%d\n",tim);
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}
D. GCD Guess
Sample input
2
1
8
1
Sample output
? 1 2
? 12 4
! 4
? 2000000000 1999999999
! 1000000000
题意:
每个询问a,b ,得到输出gcd(a+x,b+x) ,最多询问30次,问x的值是多少,范围(1<=x,a,b<=1e9)
思路:
借鉴了队友的数论的知识,如果a,b都是%(1<<i)为0的,那么gcd(a,b)也都是%(1<<i)为0的,1也一样,那就是判断每一位是否为1就行,因为最多30位,所以询问30次就能出来了,下面看代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
void solve(){
long long x = 0;
for(int i=0;i<30;i++){
long long a = (1ll<<i) - x;
long long b = a + (1ll << (i+1));
printf("? %lld %lld\n",a,b);
fflush(stdout);
long long t;
scanf("%lld",&t);
if(t % (1ll<<(i+1)) == 0) x += 1ll<<i;
}
printf("! %lld\n",x);
fflush(stdout);
}
int main(){
int _;
scanf("%d",&_);
while(_--) solve();
return 0;
}