比赛链接


A:abc转换

题目描述

牛牛有三个正整数 a,b,c ,它每次能够从三个数中选出任意两个数进行“相加,相减,相乘”中的任意一种操作,再将得到的结果赋值回三个数中的任意一个。

牛牛想知道如果采取最优策略,它至少需要几步才能使 a,b,c中至少一个数等于 0?

输入描述:


输入第一行一个正整数 T 代表案例组数。

接下来 T 行,每行三个正整数分别代表 a,b,c,。

保证:0<T,a,b,c≤1000

这个题就是直接按照题目意思来进行,可以分类成为三种情况

第一种就是里面有相等元素,那么只需要一步就能使一个数。

第二种就是a,b,c存在俩个数使得相加或者相减或者相乘等于三个数的其中一个数,那么我们可以让运算得到数替换成其他任意一个不与他相等数,在进行一次减法,就只需要俩步。

第三种就要想一下,就不是以上俩中情况时候应该怎么办了,这里楼主当时想法是第三种起码要三步起步,那我可以把任意俩个数相减使结果代替成另外那个数,然后这个数与里面相减数中的减数相加,就可以成为被减数,那我们就可以证明就最少只需要三步啦。(当然还有很多想法可以相等可以只有三步,比如俩数相加给第三个数,在自己相加给自己,再相减也是三步啦)

以下是代码

#include<bits/stdc++.h>
using namespace std;
void solve()
{int a[3];cin>>a[0]>>a[1]>>a[2];sort(a,a+3);                         //排个序方便后面的又长又臭的判断if(a[0]==a[1]||a[1]==a[2]||a[0]==a[2]){cout<<1<<'\n';return;}if(a[0]+a[1]==a[0]||a[0]+a[1]==a[1]||a[0]+a[1]==a[2]||a[1]+a[2]==a[0]||a[1]+a[2]==a[1]||a[1]+a[2]==a[2]||a[0]+a[2]==a[0]||a[0]+a[2]==a[1]||a[0]+a[2]==a[2]||a[0]*a[1]==a[0]||a[0]*a[1]==a[1]||a[0]*a[1]==a[2]||a[1]*a[2]==a[0]||a[1]*a[2]==a[1]||a[1]*a[2]==a[2]||a[0]*a[2]==a[0]||a[0]*a[2]==a[1]||a[0]*a[2]==a[2]||a[1]-a[0]==a[0]||a[1]-a[0]==a[1]||a[1]-a[0]==a[2]||a[2]-a[1]==a[0]||a[2]-a[1]==a[1]||a[2]-a[1]==a[2]||a[2]-a[0]==a[0]||a[2]-a[0]==a[1]||a[2]-a[0]==a[2]) //又长又臭的判断 里面有些不可能的判断语句但由于偷懒还是没有判别的{cout<<2<<'\n';return;}cout<<3<<'\n';}int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t;cin>>t;while(t--){solve();}return 0;
}

B 差分构造

题目描述

牛牛获得了一个可重集合,集合中有 n 个整数,现在牛牛想要利用这 n 个数构造一颗最小生成树

这里的最小生成树的权重定义为每条树上边权值的和,每条树上边的权值为其所连接两个整数的差的绝对值。

显然这样的最小生成树可能不止一颗,所以你还需要输出所有最小生成树中最长树链最短的那一颗的最长树链长度。这里的树链长度指的是树链中结点的个数,与边权和点权无关。

在本题中,你需要输出最小生成树的权值,以及所有最小生成树中最长树链的最短长度

输入描述:


第一行一个正整数 n 代表可重集中元素的个数。

第二行 n 个用空格分割的整数描述了集合中的元素。

保证:

0<n≤10^5; 集合中元素的绝对值不超过 10^9

这个题乍看以为是数据结构题,然后观察后发现是用这些数据组成一个最小生成数,发现是的贪心题,只需要把数据大小排序只后俩个相邻差的绝对值之和的就是就可以得到这组数据的最小生成树,因为这样排序后,俩个数之间相邻就是在这群数里面的绝对距离小,就满足最小生成树中的的从最小边开始选起。

然后第一问解决后,那么第二问呢,最长树的最短距离,可以发现,由上面可得里面树的组成可能有俩种模式,第一种不相同的元素相邻,第二种相同元素的相邻。那我们可以分析得,如果有不同元素相邻时候,那我们是一定要让他们之间连接成一条链的,才能满足上面所说满足最小生成树的要求,那么第二步就是相同元素之间,我们可以一开始都排序之后使这个树就是排序之后这个样子,然后里面那些相同元素的相互连接在一起的,但他们距离为零,又增大的链长,那我们可以把相同的元素选出一个作为主链上的结点,其他都一个一个直接插到这个主链结点元素上。

那么这时候可以发现,长度居然只变成去重之后长度再首位如果有相同元素就各加一,还有个特判,如果只有一个结点的话要考虑他有多少的相同元素,如果少于等于俩个,那最长链有多少个相同元素,否则最长链长度就是三啦。

以下是代码

#include<bits/stdc++.h>
using namespace std;const int N=1e5+10;int n,m;
int a[N];
int b[N];
vector<int>tr;int find(int tt)
{return lower_bound(tr.begin(), tr.end(), tt)-tr.begin();
}int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n;for(int i=0;i<n;i++) {cin>>a[i];tr.push_back(a[i]);      }sort(tr.begin(),tr.end());long long ans=0;    //答案最大可2*10^(9+5)tr.erase(unique(tr.begin(),tr.end()),tr.end());//去重for(int i=1;i<tr.size();i++)ans+=tr[i]-tr[i-1];        //最小生成树的计算m=tr.size();int res=tr.size();for(int i=0;i<n;i++){int t=find(a[i]);  //离散化了一下,来记录每一种元素有多少个b[t]++;}if(m==1)  //特判{        if(b[0]<=2) cout<<ans<<" "<<b[0];else cout<<ans<<" "<<3;return 0;}if(b[0]>=2) res+=1;     //如果最小的元素不止一个俩个就链条要增长一位if(b[m-1]>=2) res+=1;    //同理cout<<ans<<" "<<res;return 0;
}

C 向前文本编辑器

题目描述

牛牛需要一个程序帮它码一段文字,初始时文本为空,光标在文本最前方。

牛牛会发出 m条指令,指令分两种:

op s 这里 op=1 且 s是一个字符串,代表在当前光标位置插入字符串 s 并把光标移到 s的末尾(并不是整个文本的末尾)。

op x 这里 op=2 且 x 是一个正整数,代表将光标向前移动 x 个位置(保证不会超过光标前字符的个数)。

牛妹觉得这种程序已经有人做过类似的了,所以她把这题稍微修改了一点。

在原本需要输入字符串 s 的地方,牛妹将只会给出一个正整数 len 代表 s 的长度,而 s 则被定义为字符串 T 的第 1 到第 len 个字符组成的子串。

这里的字符串 T 被定义成由循环节 "abcd…xyz012…89ABCD…XYZ" ,组成的无限长字符串。

现在请你帮牛牛实现这个文本编辑器,并输出文本最后的状态(由于最后文本可能过于庞大,所以这里只需要输出文本的第 1 和第 100,200,300,400… 个字符直到文本末尾)以及光标前方字符的个数,两者用一个空格分隔。

输入描述:


第一行一个整数 m 代表操作数。

接下来 m 行,每行描述了一个操作。

保证:0<m≤10^5,所有 len 的和不超过 10^7。

输出描述:

输出共一行一个字符串和整数分别代表文本最后的状态(如题意压缩后)和光标前方字符的个数。

这个题比赛当时看错题了,没注意是输出第1到100 200 ...这个格式,以为要输出最后光标所在位置前一个字符……。

这个题第二位还是好做,最后光标的位置,op==1就加上len,op==2就减去x,主要是第一问。一开始想的是按照题目模拟一遍把字符串建立起来,不过凭直觉想了想肯定会超时,因为如果光标跳到之前以及有的连续字串段中,就需要把他们从中间拆开,然后这个维护过程对于楼主来说其实有点难想,且答案感觉可能会是对应下标的在对于他那个字串是多少位去余上62(abc...012..ABC..的长度),然后在这个abc..012..ABC..里的位置,所以pass了,也没有去尝试,可能按题目顺序也能做吧(我是菜鸡)。

所以最后就想到,可以先把操作存储下来,且设置一个值记录光标,反过来模拟,既然op==2时候是向前进x位,那么我倒着来,就是光标向后走x位,而1操作就可以向前推具体每一个位置是什么样的状态。这样的话其实就可以直接开一个字符串总长度的空位,然后光标在里面,跟着光标,在里面填字符或者是后退光标,这样就不要担心在一个连续字串中生成一个新字串啦,而这顺序的操作,在倒过来的时候可以在向前生成子串时候,遇到已经被站位置的的字串就跳过他,如何实现跳过,这就可以把原本空串想象成一个双链表,当一段被记录过后,咱们就“截掉”这段,来达成这个操作。

说这么多不如看着代码理解一下

#include<bits/stdc++.h>
using namespace std;const int N=1e5+10,M=1e7+10;int b[N][2];
int top=0;
int tt=0; //光标
int a[M][2]; // 0左 1右边
int c[M];
string s="";int n,m;
void init() //初始化一下
{a[0][1]=1;a[10000000][0]=10000000-1;for(int i=1;i<=10000000-1;i++)  //这个是模拟一下双链表,i的左边是i-1,右边是i+1{a[i][0]=i-1,a[i][1]=i+1;}for(int i=0;i<26;i++)           //来记录T 方便后面取答案s+=i+'a';for(int i=0;i<10;i++)s+=i+'0';for(int i=0;i<26;i++)s+=i+'A';
}int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);init();cin>>m;int top=0;for(int i=m;i>=1;i--){cin>>b[i][0]>>b[i][1];  //记录操作if(b[i][0]==1) {    tt+=b[i][1];       //记录光标位置top+=b[i][1];      //记录总长度是多少}else tt-=b[i][1];       //记录光标位置}int t=tt;                  //为下面计算for(int k=1;k<=m;k++){if(b[k][0]==2){          //当操作为2时候就向后推,光标位置向链条上的右边移动(当然,链条可能被截断)for(int j=b[k][1]-1;j>=0;j--,t=a[t][1]);}else{int r=t;int l;for(int i=t,j=b[k][1]-1;j>=0;j--,i=a[i][0]) //当操作为1时候就向前推,同时还可以建立一个数组来记录一下这个位置他是这个子串的第几位,光标位置向左边移动(当然,链条可能被截断){c[i]=j;l=i;} t=a[l][0];               //此时需要截断l-r这段区间的链条,先移动光标,就到这个链条的左边了a[a[l][0]][1]=a[r][1];a[a[r][1]][0]=a[l][0]; //这里就是l-r链条的左边就是a[l][0],右边是a[r][1],那就将他们连在一起,来完成截断操作}}if(1<=top){                      cout<<s[c[1]%62];   //输出第一位字符}for(int i=100;i<=top;i+=100) //按题目输出cout<<s[c[i]%62];cout<<" "<<tt;  //最后的光标位置return 0;
}

最后这个时间是不会超时哒,因为链长总共就只有10^7,那么我最多向前加子串就只会推10^7,向后也10^7,所以复杂度就是o(2*10^7)

最后,楼主是一时兴起第一次写题解,肯定有很多写的不好的,也有很多专业知识的疏忽。可能中间也有很多错别字,或者语文没有表达清楚的地方也请多多包涵。楼主只是一个比较喜欢做做算法题的萌新,还有更多需要学习地方。如果对于我的题解有不懂的,欢迎评论区留言,来解答。也欢迎大佬来指导一下我的各个方面不足。谢谢~

牛客练习赛103A-C的个人解题思路相关推荐

  1. 解题报告(一)C、(牛客练习赛41 F)简单数学题(数论 + FWT)(3.5)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  2. 牛客练习赛81 E. 小 Q 与函数求和 1( “简单莫比乌斯反演” ,欧拉函数性质)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 牛客练习赛81 E. 小 Q 与函数求和 1( "简单莫比乌斯反演" ) Prob ...

  3. 牛客练习赛34 E little w and Digital Root(数位dp)

    title: 牛客练习赛34 E little w and Digital Root(数位dp) date: 2018-12-17 22:38:37 tags: 数位dp categories:ACM ...

  4. 牛客练习赛34 - C little w and Segment Coverage(思维、树状数组)

    title: 牛客练习赛34 - C little w and Segment Coverage(思维.树状数组) date: 2018-12-15 16:36:55 tags: [树状数组,思维] ...

  5. 牛客练习赛52 | C | [烹饪] (DP,裴蜀定理,gcd)

    牛客练习赛52 C 烹饪 链接:https://ac.nowcoder.com/acm/contest/1084/C来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 327 ...

  6. 牛客练习赛73 D 离别(线段树+右端点排序离线查询)

    牛客练习赛73 D 离别 思路: 对于每一个固定的右端点i,我们都找到一个区间(l,r)使得区间中的点为左端点时 里面最大的的种数为k. 这个可以用队列或者vector来维护. 然后我们对于q个查询, ...

  7. 牛客练习赛75 D 减数游戏(队列优化(需要取模的)堆)

    牛客练习赛75 D 减数游戏 思路:写一下式子可以发每次选择最小的两个数进行操作,最后得到的答案会是最大的,那我们可以将它放进一个最小堆中来维护,但是里面的数是需要取模的,当它取模的时候,将会变小.那 ...

  8. 妄想集合(牛客练习赛90)

    妄想集合(牛客练习赛90) 题意: 开始有 n 个可重集合,开始时每一个集合中都有一个数,有 m 个操作. Quant l r x\text{Quant l r x}Quant l r x:往编号在 ...

  9. 踩不出足迹(牛客练习赛88 )

    踩不出足迹(牛客练习赛88 ) 题意: 长度为n的数组a,每个数是一个k位二进制 定义一下操作: 令第一次得到的结果为 a1a_1a1​.你需要从第二个数开始,每次可以选择与上一次得到的结果异或或者同 ...

  10. 牛客练习赛29 题解

    牛客练习赛29 A. 可持久化动态图上树状数组维护01背包 题解 这题跟标题没有任何关系- 贪心的使得负数删除的时候下标尽可能大,然后正数的时候下标尽可能小. 观察到每个数下标最大的时候就是它的初始下 ...

最新文章

  1. 路由器简介一:路由器概念、基本结构及分类
  2. flask学习笔记之blueprint
  3. wps不能打印_Excel表格怎么打印在一张纸上?
  4. 浙江万里学院计算机专业宿舍,浙江万里学院宿舍条件,宿舍几人间环境好不好(图片)...
  5. java泛型学习三:受限制的通配符以及泛型方法
  6. 动手开发第一个 Cypress 测试应用
  7. 软件项目组织管理(九)项目人力资源管理
  8. 这是啥?也太秀了吧?
  9. 定义m是第一个数,之后的每个数都是前一个的平方根,一共有n个数,计算总和。
  10. 快手小视频批量下载高清无水印软件 快手短视频批量下载高清无水印软件
  11. 第一讲 ISO 17799/27001 标准简介
  12. 字节跳动小程序平台审核常见被拒情形
  13. Docker网络与资源控制
  14. windows源文件名称大于文件系统支持的长度无法删除问题
  15. mDNS原理的简单理解
  16. 分享Silverlight/WPF/Windows Phone一周学习导读
  17. HTML+CSS简单漫画网页设计成品--(红猪(9页)带注释)
  18. texlive+texstudio数学建模排版
  19. CAN 常见错误排查
  20. 正则表达式转NFA,DFA,最小化DFA

热门文章

  1. Django数据库常用字段及参数
  2. 基于Python实现网络路由实验【100010467】
  3. 二十世纪计算机技术逐渐发展起来,机电一体化在建筑智能化工程中的技术分析及应用...
  4. 耶鲁女孩刘畅教你循序渐进背单词
  5. mac linux 字符,如何让Mac系统的echo -e命令输出中文等Unicode编码字符(系统默认bash版本升级修改)...
  6. 【Hadoop】YouTube 视频数据集分析实验 (原理+过程+代码)
  7. linux web全栈编辑器,sx html5全栈可视编辑器下载
  8. cling-java,android的协议栈
  9. python 翻译例句_Python实现句子翻译功能
  10. 测试工具研发_(2)测试框架驱动之布局调整