A题
原题链接:https://codeforces.com/problemset/problem/1296/A
相关tag:简单思维

我们每次操作可以把数组中的一个数变为另一个数,那么如果这两个数同为奇数或者同为偶数的话,操作后是不会对整个数组总和的奇偶性造成影响的。只有奇数变为偶数或者偶数变为奇数的时候,才会对整个数组总和的奇偶性造成影响。

那么我们可以统计出原数组中奇数的个数记为num1,偶数的个数记为num2。
整个数组总和的奇偶性是由奇数的个数决定的,当num1为奇数的时候,整个数组的总和一开始就是奇数,无需更改。
如果num1为偶数,此时整个数组的总和为偶数,就需要让某一个奇数变为偶数,或者一个偶数变为奇数,那么就要求原数组中奇数和偶数都存在。也就是num1和num2均不为0,才能通过操作变换使得整个数组的总和从偶数变为奇数。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;int main()
{IOSint t;cin>>t;while(t--){int n;cin>>n;int num1=0,num2=0;while(n--){int x;cin>>x;if(x&1) num1++;//判断x是奇数还是偶数else num2++;}if(num1&1) cout<<"YES"<<endl;//如果num1是奇数,原数组中奇数出现了奇数次,数组总和为奇数,无需操作已经满足else if(num1&&num2) cout<<"YES"<<endl;//num1是偶数,原数组总和为偶数,需要奇数和偶数均存在才能改变总和的奇偶性else cout<<"NO"<<endl;}
}

B题
原题链接:https://codeforces.com/problemset/problem/1296/B
相关tag:暴力,模拟,贪心
当然你也可以选择推公式,都可以,这里给出暴力做法。

我们贪心策略,当前手上个位数上的钱都先放着不用,其余的钱都拿去买,拿了返利后,重复之前的操作,直到钱的数量小于10无法得到返利为止。

容易证得,最多两次上述操作,就可以使得我们手上剩余钱的位数-1,因此暴力计算时间完全足够。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;int main()
{IOSint t;cin>>t;while(t--){int n;cin>>n;int ans=0;while(n>9)//当还可以得到返利时就不断重复把除了个位的钱都花掉,贪心去拿返利{ans+=n/10*10;n=n%10+n/10;}cout<<ans+n<<endl;}
}

C题
原题链接:https://codeforces.com/problemset/problem/670/C
相关tag:离散化,《算法竞赛进阶指南》第33页例题原题。

当然也可以用map来做,这里还是更希望能去学习一下离散化。
注意到这道题数据虽然只有2e5个,但是数值非常大,最大有1e9,我们是开不了1e9大小的数组来直接记录每个数出现了几次的。
但是数组也就2e5个,加上下面安排中的数字,总共也就最多6e5种不同的数字。可以通过离散化把这些数字映射到1-6e5这6e5个整数里。

离散化具体操作去看书或者博客去学吧。这里给出stl的实现和数组实现两种方案。

stl实现的离散化代码:

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=2e5+7;
const double eps=1e-6;
const int mod=1e9+7;vector<int>origin;//用于离散化int find(int x)//在离散化数组中查找当前x所在的位置,这里也可以自己手写个二分
{return (int)(lower_bound(origin.begin(),origin.end(),x)-origin.begin());
}int num[maxn];//记录m个数字
int cas[maxn*3];//cas[i]记录origin[i]代表的数字出现了几次,注意这里要开三倍大小,因为后面m种安排的节目数字不一定在num中出现过
int x[maxn],y[maxn];//x[i]代表第i种安排的第一个节目,y[i]是第i种安排的第二个节目
int feichang[maxn],yiban[maxn];//feichang[i]代表第i种安排非常开心的有几个人,yiban[i]代表第i种安排一般开心的有多少个人
int n;int main()
{IOScin>>n;for(int i=1;i<=n;i++){cin>>num[i];origin.push_back(num[i]);}int m;cin>>m;for(int i=1;i<=m;i++) {cin>>x[i];origin.push_back(x[i]);}for(int i=1;i<=m;i++) {cin>>y[i];origin.push_back(y[i]);}//注意要把安排里的数字也压入origin,因为这些数字可能在前面的num数组中未出现sort(origin.begin(),origin.end());origin.erase(unique(origin.begin(),origin.end()),origin.end());//离散化过程for(int i=1;i<=n;i++) cas[find(num[i])]++;//统计每个数出现了几次int ans=1;for(int i=1;i<=m;i++){feichang[i]=cas[find(x[i])];yiban[i]=cas[find(y[i])];if(feichang[i]>feichang[ans]||feichang[i]==feichang[ans]&&yiban[i]>yiban[ans]) ans=i;}cout<<ans<<endl;
}

数组实现的离散化代码:

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=2e5+7;
const double eps=1e-6;
const int mod=1e9+7;int origin[maxn*3];//用于离散化
int tot=0,now=1;//tot代表离散化前origin数组中保存了几个数,now代表离散化后origin数组中保存了几个数int find(int x)//在离散化数组中查找当前x所在的位置,这里也可以自己手写个二分
{return (int)(lower_bound(origin,origin+now,x)-origin);
}int num[maxn];//记录m个数字
int cas[maxn*3];//cas[i]记录origin[i]代表的数字出现了几次,注意这里要开三倍大小,因为后面m种安排的节目数字不一定在num中出现过
int x[maxn],y[maxn];//x[i]代表第i种安排的第一个节目,y[i]是第i种安排的第二个节目
int feichang[maxn],yiban[maxn];//feichang[i]代表第i种安排非常开心的有几个人,yiban[i]代表第i种安排一般开心的有多少个人
int n;int main()
{IOScin>>n;for(int i=1;i<=n;i++){cin>>num[i];origin[tot++]=num[i];}int m;cin>>m;for(int i=1;i<=m;i++) {cin>>x[i];origin[tot++]=x[i];}for(int i=1;i<=m;i++) {cin>>y[i];origin[tot++]=y[i];}//注意要把安排里的数字也压入origin,因为这些数字可能在前面的num数组中未出现sort(origin,origin+tot);for(int i=1;i<tot;i++)if(origin[i]!=origin[now-1]) origin[now++]=origin[i];//离散化过程for(int i=1;i<=n;i++) cas[find(num[i])]++;//统计每个数出现了几次int ans=1;for(int i=1;i<=m;i++){feichang[i]=cas[find(x[i])];yiban[i]=cas[find(y[i])];if(feichang[i]>feichang[ans]||feichang[i]==feichang[ans]&&yiban[i]>yiban[ans]) ans=i;}cout<<ans<<endl;
}

D题
原题链接:https://codeforces.com/problemset/problem/892/B
相关tag:双指针,或者也可以叫尺取法,滑动窗口,名字并不重要,掌握思想是关键。

这里我们可以从后往前看,用now来记录当前仍然为黑色的数字中,最右侧的是哪一个,num[i]记录第i个数字会把自己前面几个数染成白色。
随着循环借助当前的位置i减去num[i]-1,得到i位置对前面的进行染色后,仍然为黑色的最右侧下标是多少,和now比较并更新now。

循环内的操作都是O(1)的,总复杂度O(n)

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;
const int xx=1;int n;
int num[maxn];int main()
{IOScin>>n;for(int i=1;i<=n;i++) cin>>num[i];int ans=0;int now=n;//now记录当前仍然为黑色的数字中,最右侧的是哪一个for(int i=n;i>0;i--)//从后往前看{if(i<=now) ans++;//如果当前下标在i前,代表当前位置仍然为黑色if(num[i]) now=min(now,i-num[i]-1);//更新now}cout<<ans<<endl;
}

E题
原题链接:https://codeforces.com/problemset/problem/520/B
相关tag:数学,dfs/bfs跑最短路径

这道题结论做法当然好,但是我还是更希望大家能看一下,这种问题是怎么样转换成一个图论可以解决的模型的,并且学习一下dfs/bfs算法。

这道题我们可以把每个值看成一个点,那么点之间的边是什么呢,那就是x到x-1,x到2x,有这两类边,对应题目给我们的两种操作。

我们建图之后直接找x到y的最短路径就行了,可以借助bfs或者dfs剪枝来是实现。

dfs实现:

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;int x,y;int dis[maxn];//dis[i]记录从x到i最少要几次操作void dfs(int now,int d)//now代表当前数字是多少,d代表从x到now经过了多少次操作
{if(dis[now]<=d) return;//如果now数字已经有了更优的到达方式,不再进行下面的操作dis[now]=d;//更新x到now需要的最少次数if(now>=y) {dis[y]=min(dis[y],d+now-y);return;}//如果当前数值已经大于等于目标y了,就没必要再乘2了,直接-1到值y为止dfs(now*2,d+1);//两种操作,一种是当前数值乘以2if(now>1) dfs(now-1,d+1);//另一种操作,当前数值-1
}int main()
{IOScin>>x>>y;for(int i=0;i<maxn;i++) dis[i]=INF;dfs(x,0);cout<<dis[y]<<endl;
}

bfs实现:

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=1e6+7;
const double eps=1e-6;
const int mod=1e9+7;int x,y;int dis[maxn];//dis[i]记录从x到i最少要几次操作
bool flag[maxn];//flag[i]记录数字i是否已经进过bfs过程的队列void bfs()
{queue<int>Q;Q.push(x);dis[x]=0;while(Q.size()){int now=Q.front();Q.pop();if(now==y) break;//如果已经走到数字y了,结束bfs过程if(!flag[now*2]){if(now*2>=y) dis[y]=min(dis[y],dis[now]+1+now*2-y);else{Q.push(now*2);dis[now*2]=dis[now]+1;flag[now*2]=1;}}if(now>1&&!flag[now-1]){Q.push(now-1);dis[now-1]=dis[now]+1;flag[now-1]=1;}}
}int main()
{IOScin>>x>>y;dis[y]=INF;if(x>=y) dis[y]=x-y;else bfs();cout<<dis[y]<<endl;
}

F题
原题链接:
相关tag:离线,并查集

离线之后反向操作,就把删点变成加点了,然后就可以用并查集来解决问题了。
懂得自然懂,直接丢代码。

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=1e5+7;
const double eps=1e-6;
const int mod=1e9+7;bool flag[maxn];
ll num[maxn];
ll ans[maxn];
int ope[maxn];
int n;int fa[maxn];
ll sum[maxn];int ask(int x) {return fa[x]==x?x:fa[x]=ask(fa[x]);}void merge(int x,int y)
{fa[x]=y;sum[y]+=sum[x];
}int main()
{IOScin>>n;for(int i=1;i<=n;i++) cin>>num[i];for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=n;i++) cin>>ope[i];ans[n]=0;for(int i=n;i>1;i--){ans[i-1]=ans[i];flag[ope[i]]=1;sum[ope[i]]+=num[ope[i]];ans[i-1]=max(ans[i-1],sum[ope[i]]);if(ope[i]>1&&flag[ope[i]-1]){merge(ask(ope[i]),ask(ope[i]-1));ans[i-1]=max(ans[i-1],sum[ask(ope[i])]);}if(ope[i]<n&&flag[ope[i]+1]){merge(ask(ope[i]),ask(ope[i]+1));ans[i-1]=max(ans[i-1],sum[ask(ope[i])]);}}for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
}

G题
原题链接:https://codeforces.com/problemset/problem/1339/D
相关tag:树上构造

#include<bits/stdc++.h>
#define ll long long
#define INF 0x7f7f7f7f //2139062143
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const int maxn=1e5+7;
const double eps=1e-6;
const int mod=1e9+7;bool jishu=0,oushu=0;
int dp[maxn],n;
vector<int>dir[maxn];void dfs(int pre,int now,int deep)
{bool leaf=0;if(dir[now].size()==1){if(deep&1) jishu=1;else oushu=1;}for(int i=0;i<dir[now].size();i++){if(dir[now][i]==pre) continue;dfs(now,dir[now][i],deep+1);if(dir[dir[now][i]].size()==1) leaf=1;else dp[now]+=dp[dir[now][i]]+1;}dp[now]+=leaf;
}int main()
{IOScin>>n;for(int i=1;i<n;i++){int a,b;cin>>a>>b;dir[a].push_back(b);dir[b].push_back(a);}int tar=-1;for(int i=1;i<=n;i++)if(dir[i].size()>1) {tar=i;break;}dfs(-1,tar,0);if(jishu&&oushu) cout<<3<<' ';else cout<<1<<' ';cout<<dp[tar]<<endl;
}

ZAFU_2021_2_17_2021寒假个人赛第四场题解相关推荐

  1. 北方大学 ACM 多校训练赛 第四场 题解

    A. 恶魔包毁灭世界 已知一张二分图,问哪些边是二分图的可行边? 先跑最小流,再把残余网络建图,几个重要结论是: ·最小割的可行边(满流&&2点不在一个SCC中) ·最小割的必行边(可 ...

  2. 题解报告(CDUT暑期集训——第四场)

    题解报告(CDUT暑期集训--第四场) Problem D. Nothing is Impossible HDU - 6335 思路:水题 排个序循环判断就出来了 AC代码 #include<s ...

  3. 2021UPC第十四场部分题解(ADFL)

    2021UPC第十四场部分题解(ADFL) 文章目录 2021UPC第十四场部分题解(ADFL) 前言 A 火星人问题 F: Card Game for Three L Daisy Chains D: ...

  4. 2020牛客暑期多校训练营(第四场)

    2020牛客暑期多校训练营(第四场) 这场属实有点难受 文章目录 A Ancient Distance B Basic Gcd Problem 题目 代码: C Count New String D ...

  5. 1.9UPC寒假个人训练第一场

    1.9UPC寒假个人训练第一场 问题 A: 数列 问题 B: 烦恼 问题 C: 停车计费 问题 D: 小区评比 问题 E: 贪婪的国王 问题 F: 等边三角形 问题 G: 甜蜜的烦恼 问题 H: 冰壶 ...

  6. 项链(牛客竞赛2020-普及组第四场-T4)

    项链(牛客竞赛2020-普及组第四场-T4) 题目 原题链接 样例 输入1 4 3 4 3 -2 1 1 2 2 3 3 4 输出1 7 1 说明1 第一组样例,最优路径为1→2→3→41 \to 2 ...

  7. 2022湖南多校对抗赛第四场

    2022湖南多校对抗赛第四场 队伍排名 第一 第二 第三 中南大学2队 湖南大学2队 国防科技大学4队 团体成绩 取每个学校正式队伍前四名 学校 总题数 中南大学 30 国防科技大学 27 湘潭大学 ...

  8. 2021牛客OI赛前集训营-提高组(第四场) T2空间跳跃

    2021牛客OI赛前集训营-提高组(第四场) 题目大意 给你三个整数 n , d , l n,d,l n,d,l, n n n为正整数.负整数或0, d , l d,l d,l为正整数,你现在有一个数 ...

  9. “战疫杯”在线邀请赛——第五场题解

    "战疫杯"在线邀请赛--第五场题解 题目详情 - 1 感染源在哪里 (pintia.cn) 通过最近的一次核酸检测,疫情防控小组检测到了若干个阳性人员,通过调取行程码数据,防控小组 ...

最新文章

  1. 反射拷贝对象的思路:
  2. 我在 Spring 的 BeanUtils 踩到的那些坑,千万不要犯!
  3. 如何从Oracle数据库中的表中获取列名(字段名)列表?
  4. hi3798mv300是什么手机_华为海思电视芯片hi3798mv300 硬件参数如何?
  5. 转载——CVE-2019-0807
  6. win10(UEFI)和Ubuntu双系统安装,无法进入ubuntu。
  7. 【python】编程学习练习题-2
  8. mongodb 连接失败
  9. 【Java定时任务调度工具】Timer
  10. php中常用的字符串获取函数mb_strcut实例解释
  11. python时间序列按频率生成日期的方法
  12. 吉林大学线性代数知识点及解题方法
  13. 搭建Vgg16训练CIFAR10数据集
  14. 程序员学习的网站(持续收集中)
  15. TensorFlow Serving 入门教程(Windows)
  16. 如何读懂EDIFACT报文?
  17. matlab水下机器人,水下机器人路径控制与仿真
  18. 磁盘块管理器DiskBlockManager
  19. Week_eight
  20. java画星星_用java画色彩斑斓的星星

热门文章

  1. 网络与系统安全笔记------网络安全协议
  2. 职业经验 聊一聊职业发展
  3. IDL学习:语法基础-字符串
  4. 《DBA: DISTRIBUTED BACKDOOR ATTACKS AGAINST FEDERATED LEARNING》阅读笔记
  5. W: Possible missing firmware /lib/firmware/i915/kbl_guc_ver9_14.bin for module i915
  6. java二级考试试题题型有哪些_哪里有计算机二级题库?计算机二级考试题型有哪些?...
  7. 移动硬盘变为RAW格式后的修复
  8. CarSim与Simulink联合仿真——ABS
  9. 中关村GHOST XP SP3纯净装机自选CD版2011V3(NTFS)
  10. 博客设置中 html,博客大巴Blog设置 -如何在自定义Html中添加背景音乐?