Codeforces Round #694 (Div. 2) A~D + F 题解
A. Strange Partition
-
解题思路
求最大值易知,就是每个元素向上取整求和即可。对于最小值,我们需要减少向上取整的次数,即最大化利用整除,这一步我们可以将所有的余数都加起来,最后再进行向上取整。 -
AC代码
/**
*@filename:A_Strange_Partition
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-02 19:08
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;
int t,n,x;
int a[N];
void solve(){
ll ans1 = 0,ans2 = 0,temp = 0;
for(int i = 1; i <= n; ++ i){
ans1 += a[i] / x;
ans2 += a[i] / x + (a[i] % x != 0);
temp +=(a[i] % x);
}
cout << ans1 + temp / x + (temp % x != 0) << " " << ans2 << endl;
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%d", &n , &x);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
}
return 0;
}
B. Strange List
-
解题思路
一道模拟题,我们注意,模拟时需要将相同的数一起处理。所以我们可以用pair对来存储其值和连续出现次数,用队列来模拟。注意,一但有不合法数据,机器会立即停止运作。所以我们需要设置标志变量来判断,以及时退出。 -
AC代码
/**
*@filename:B_Strange_List
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-02 19:13
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 100000 + 5;
const int P = 1e9+7;
int t,n,x;
queue<pii> q;
void solve(){
ll ans = 0;
pii head;
bool flag = true;//机器运作标志。
while(!q.empty()){
head = q.front();
q.pop();
ans += 1LL * head.first * head.second;
if(head.first % x != 0)flag = false;
if(flag){
q.push({head.first / x , head.second * x});
}
//cout << head.first << " " << head.second << endl;
}
printf("%lld\n",ans);
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%d", &n, &x);
int temp;
while(!q.empty())q.pop();
for(int i = 1; i <= n; ++ i){
scanf("%d",&temp);
q.push({temp,1});
}
solve();
}
return 0;
}
C. Strange Birthday Party
-
解题思路
贪心题。对于每个人标注的 k k k,如果其越大,那么可供的选择也就越多,而对于花费 c c c序列也是递增的,所以我们可以先处理 k k k标注大的,这样总能保证我们将最小的 c c c选掉,得到最优解。 -
AC代码
/**
*@filename:C_Strange_Birthday_Party
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-02 20:36
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300000 + 5;
const int P = 1e9+7;
int t,n,m,k[N],c[N];
void solve(){
sort(k + 1 ,k + 1 + n,greater<int>());
int d = 1;
ll sum = 0;
for(int i = 1; i <= n; ++ i){
if(k[i] >= d)sum += c[d ++ ];
else sum += c[k[i]];
}
cout << sum << endl;
}
int main(){
scanf("%d", &t);
while(t -- ){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i){
scanf("%d", &k[i]);
}
for(int i = 1; i <= m; ++ i){
scanf("%d", &c[i]);
}
solve();
}
return 0;
}
D. Strange Definition
- 解题思路
我们先来解释一下相邻,如果 ( x , y ) (x,y) (x,y)满足 l c m ( x , y ) g c d ( x , y ) \frac{lcm(x,y)}{gcd(x,y)} gcd(x,y)lcm(x,y)得到的结果是可以开平方的,则说明 ( x , y ) (x,y) (x,y)相邻。我们对这个式子做一下变换,即因为 l c m ( x , y ) = x y g c d ( x , y ) lcm(x,y)=\frac{xy}{gcd(x,y)} lcm(x,y)=gcd(x,y)xy,所以 l c m ( x , y ) g c d ( x , y ) = x y g c d ( x , y ) 2 \frac{lcm(x,y)}{gcd(x,y)}=\frac{xy}{gcd(x,y)^2} gcd(x,y)lcm(x,y)=gcd(x,y)2xy。则表明如果 x , y x,y x,y相乘是一个完全平方数,则说明 x , y x,y x,y相邻,易知相邻具有传递性。
每经过一秒,相邻的元素 x x x会被其所有相邻元素的乘积代替掉(包括它本身),即倘若 x , y , z x,y,z x,y,z相邻,那么经过一秒后 x , y , z x,y,z x,y,z均会变成 x × y × z x\times y\times z x×y×z。所以我们可以相邻的元素分组,分完组后,组别中如果只有奇数个元素,那么它是不会变的,因为它的指数还是奇数,而组别中如果有偶数个元素,那么经过一秒后它们会成为一组,即只存在一组偶数个元素的组别,因为经过这次元素的指数都是偶数。所以我们关键就是利用质因数分解来分组,对于偶数次,我们不关心,我们主要是要存储奇次质因子。这可以利用map实现。然后,求 m a x d max_d maxd时,对于 0 0 0秒的时候,正常获取每个组别的最大元素数量即可,而对于 1 1 1秒及之后的,我们需要将偶数元素的组合并,然后与奇数次的比较得到最大值即可。 - AC代码
/**
*@filename:D_Strange_Definition
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-03 09:20
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 300000 + 5;
const int P = 1e9+7;
int t,n,q;
ll w;
int primer[N],cnt;
map<int,int> p;//存储质因子。
void init(){
for(int i = 2; i < N; ++ i){
if(!primer[i]){
primer[++primer[0]] = i;
for(int j = i * 2; j < N; j += i){
primer[j] = 1;
}
}
}
}
void get(int x){
int ans = 1;
for(int i = 1; i <= primer[0]; ++ i){
int temp = 0;
while(x % primer[i] == 0){
temp++;
x /= primer[i];
}
if(temp % 2 == 1){
ans *= primer[i];//获取奇质因子。对于偶数因子本来就满足,无需考虑。
}
if(x < 1LL * primer[i] * primer[i])break;
}
if(x != 1){
ans *= x;
}
p[ans] ++;
}
void solve(){
int ans1 = 0,ans2 = 0;
for(auto &it: p){
ans1 = max(ans1,it.second);
if(it.second % 2 == 0)ans2 += it.second;
else if(it.first == 1) ans2 += it.second;//将偶数因子累加起来。
}
ans2 = max(ans1,ans2);
scanf("%d", &q);
while(q -- ){
scanf("%lld", &w);
printf("%d\n",w ? ans2 : ans1);
}
}
int main(){
init();
scanf("%d", &t);
while(t -- ){
scanf("%d", &n);
p.clear();
int temp;
for(int i = 1; i <= n; ++ i){
scanf("%d", &temp);
get(temp);
}
solve();
}
return 0;
}
F. Strange Housing
-
解题思路
就是一个染色问题。题目中要求任意房屋都可通行,且一条边上只能有一端住老师。对于这种问题,我们知道如果图连通,则必定有且,这根据染色思想可得。那么,我们怎么去放置呢?我们的思路就是遍历所有点,如果当前节点没有染色,且相邻的所有节点都没有染色,就染色。否则不染色。
这样,即可实现题目需求。 -
AC代码
/**
*@filename:F_Strange_Housing
*@author: pursuit
*@csdn:unique_pursuit
*@email: 2825841950@qq.com
*@created: 2021-07-03 11:09
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 600000 + 5;
const int P = 1e9+7;
int t,n,m,u,v;
struct node{
int to,next;
}edges[N];
bool vis[N],flag[N];//vis[i]表示i节点是否已经访问过,flag[i]表示i节点是否已经染色。
int head[N],tot;
void init(){
for(int i = 1; i <= n; ++ i){
vis[i] = false;
flag[i] = false;
head[i] = false;
}
tot = 0;
}
void add(int u,int v){
edges[++tot].to = v;
edges[tot].next = head[u];
head[u] = tot;
}
bool check(){
//检查图是否连通。以1作为起点,判断是否能访问到n个顶点。
int num = 1;
queue<int> q;
q.push(1);
vis[1] = true;
while(!q.empty()){
int idx = q.front();
q.pop();
for(int i = head[idx]; i; i = edges[i].next){
if(!vis[edges[i].to]){
vis[edges[i].to] = true;
num ++;
q.push(edges[i].to);
}
}
}
return num == n;
}
void solve(){
if(!check()){
puts("NO");
}
else{
//否则一定连通。
puts("YES");
queue<int> q;
q.push(1);
for(int i = 1; i <= n; ++ i){
vis[i] = false;
}
vis[1] = true;
int res = 0;
while(!q.empty()){
int idx = q.front();
q.pop();
bool flag1 = false;
for(int i = head[idx]; i; i = edges[i].next){
if(!vis[edges[i].to]){
vis[edges[i].to] = true;
q.push(edges[i].to);
}
//检查相邻顶点是否染色。
if(flag[edges[i].to]){
flag1 = true;
}
}
//检查是否有必要染色。
if(!flag1){
flag[idx] = true;
res ++;
}
}
printf("%d\n",res);
for(int i = 1; i <= n; ++ i){
if(flag[i]){
printf("%d ",i);
}
}
printf("\n");
}
}
int main(){
scanf("%d", &t);
while(t -- ){
init();
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++ i){
scanf("%d%d", &u, &v);
add(u,v);
add(v,u);
}
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】