Codeforces Round #501 (Div. 3) 翻船记
Posted lyfoi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #501 (Div. 3) 翻船记相关的知识,希望对你有一定的参考价值。
A Points in Segments
翻译
现在有一个数轴,上面会有(M)个点,标号为(1)到(N),现在给你在数轴上的条(N)线段的起始与终止的点,问哪几个点没有被这样线段覆盖,从小到大输出。
思路
签到题目。感觉几乎和一道题一样:校门外的树,撞题是很尴尬。思路差不多,即为开一个数组,全部赋值为(0),输入的线段的时候,将其起点与终点的全部的点赋值为(1),最后跑一下看看那些为(0)的点就完事了。
Code
#include<iostream>
using namespace std;
int book[1001];//默认为0
int main()
{
int n,k,t=0;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
int a,b;
cin>>a>>b;
for(int j=a;j<=b;j++)//标记线段的区间
book[j]=1;
}
for(int i=1;i<=k;i++)
if(book[i]==0)//0即为没有覆盖
t++;
cout<<t<<endl;
for(int i=1;i<=k;i++)
if(book[i]==0)
cout<<i<<" ";
return 0;
}
B Obtaining the String
翻译
给你两个字符串(s)与(t),你每次可以交换字符串(s)种相邻两个字符,请你输出字符串(s)变成(t)的步骤(如果输出(k),代表交换了(k)与(k+1)),如果有多组解,随意输出一种即可。
思路
这道题一开始考虑复杂了,实际不难,这题是(SPJ),我是这么想的:我们都知道任意(1)个字符可以通过交换相邻的两个字符来跑遍整个字符串。
进而可以得出:只要我们可以枚举字符串(t)的每一个字符,并让(j)从这个字符开始(这是为了方便后面的交换),找到字符串(s)中的第一个与他相等的字符,如果是合法的情况,那么每个字符都能对上去才对,所以找不到直接(-1);然后从与其一样的字符开始向其进军,一直到他为止,中间的步骤要记录下来。
然后,完事了,代码有注释。看来(Div3)对于我这种蒟蒻不算太水啊!
Code
#include<iostream>
#include<algorithm>
using namespace std;
int n,num,f,ans[1000001];
string s,t;
int main()
{
cin>>n>>s>>t;
for(int i=0;i<n;i++)
{
f=false;
int j;
for(j=i;j<n;j++)
if(t[i]==s[j])
{
f=true;//找到第一个相等的并跳出,记录为找到
break;
}
if(f==false)
return cout<<-1<<endl,0;
for(int k=j-1;k>=i;--k)
{
ans[++num]=k;
swap(s[k],s[k+1]);
}
}
cout<<num<<endl;
for(int i=1; i<=num; i++)
cout<<ans[i]+1<<" ";//因为我们是下标从0开始,所以要加一
return 0;
}
C Songs Compression
翻译
给你(n)首歌,每首歌压缩前大小为(a_i),压缩后大小为(b_i),你现在的空间大小为(m),问你至少需要压缩几首歌才能使得你装下所有的歌?
思路
一看是一道贪心,思路就是把压缩后与压缩前的从大到小排序后减去正常情况下要的空间,看看什么时候能够空间或者答案是(-1)。
然鹅就这么简单吗?不的,看看下面的几个坑点:
请开
long long
,会爆int
的,这点我注意到了请注意压缩前的大小可能比压缩后的大小还要小!((PS:)我就因为这个点死在第七个点上,原因是这是个英文题,我只是个准八年级学生,直接谷歌翻译,能理解就不错了(QAQ),看来这是传说中的反常压缩?不过我还算聪明,最后在(11:55)放弃了这道题,并且去干(D)题,不过刚刚看完题目就十二点整了,没办法只好第二天下午补上(D)题了(QAQ),啊啰嗦这么多了)
排完顺序后一定要先判断内存够不够,再减去!(我一开始错在这,(debug)了几分钟)。
有点靠基本功的感觉啊,坑多死了(www)。
Code
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,m,c[1000001],ans,sum;//long long许多人爆了,我~~比较细心~~,没有炸233
bool comp(int a,int b)
{
return a>b;
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
{
int a,b;
cin>>a>>b;
c[i]=abs(a-b);//注意,压缩后大小可能差为负数,这就是我这题一直死在第七个点的原因
sum+=a;
}
sort(c+1,c+n+1,comp);//排序
for(int i=1; i<=n; i++)
{
if(sum<=m)//有点坑,但是~~细心的我~~还是注意到了
break;
else
ans++,sum-=c[i];//减去
}
if(sum>m)
cout<<-1<<endl;
else
cout<<ans<<endl;
return 0;
}
Walking Between Houses
翻译
给你一条数轴(出题人很喜欢数轴啊),上面有排列着(n)个点,编号为(1)到(n)(你开始在(1))。每次你要从一个点移动到另一个点(可以重复)。移动距离为两点坐标之差的绝对值,问你是否能否在(k)次机会内里一共移动(s)距离,并输出方案。
思路
第四题还是比较难的。
毫无疑问还是贪心(出题人很喜欢贪心啊)!那么我们分类讨论,先看不合法的情况
无论如何走你也走不到那个距离
无论如何走你也会走超那个距离
看来只要能走到那个距离除外都是不合法的,因此就一个走超和走不到(我没废话!)。
那么如何解决?很简单,走不到就是每次你从最左边走到最右边,再从最右边走到最左边,这样循环下去,一直到你走完了还不到。
走超了就是你每次走一个距离,进行(k)次后还是大于(s)。
那么这两个代码好写极了,不用我教你吧^_^。
到了合法的情况,受到不合法的启发,我们可以想到这样的方法:每一次啊,先从最左边走到最右边,再从最右边走到最左边,循环下去,一直到你剩下的距离不足(n-1)((n-1)就是数轴两个端点间的距离)的时候啊,直接走完即可(由于在此期间你只会位于数轴的两个端点)。
但是不会那么简单的(QAQ),直接走完可不行啊,如果要走(32)那么远,(4)下子走完,数轴有(11)个点。照我们说的,当还有两个长度的时候,我们一步走完,呀!怎么还有一下!!
所以说,我们可以这样想:当剩下的距离不足(n-1)的时候,我们尝试分成多部走,很多种方法,我的有点麻烦,某位大佬写的是:走(s-k)((s)是剩下的距离)的步数。感觉自己恍然大悟了(不懂你可以算算,由于是(s-k),这样就巧妙的拆分成了多部分)!
一定要用long long
((CF)的题就这个尿性)!
恐怕上述的方法是最简单的方法之一了吧,上代码(有两个细节在代码里注释了):
Code
#include<iostream>
using namespace std;
int main()
{
long long n,k,s,a=1;
cin>>n>>k>>s;
if(s>(n-1)*k||k>s)
return cout<<"NO"<<endl,0;
cout<<"YES"<<endl;
while(k--)
{
int r=min(s-k,n-1);//选区n-1与s-k中最小的,因为当s-k比n-1大的时候,我们要先消去
s-=r;
if(a+r<=n)//看看往哪个方向走。
a+=r;
else a-=r;
cout<<a<<" ";
}
return 0;
}
可以来一起(AFO)么!
以上是关于Codeforces Round #501 (Div. 3) 翻船记的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #501 (Div. 3) F. Bracket Substring
Codeforces Round #501 (Div. 3) ABDE1E2
Codeforces Round #501 (Div. 3) 翻船记
Codeforces Round #501 (Div. 3) B Obtaining the String