题目链接: Codeforces Round #822 (Div. 2)
A. Select Three Sticks
题意:
签到题,给你一个数组,你可以对每个数进行+1、-1的操作,要你找出最小操作数使得数组中有三个数可以组成等边三角形。
题解:
刚开始脑子没转过来,后面发现只要对数组排个序,然后利用滑动窗口的思想,三个值为一组开始滑动,每次找出三个数要组成等边三角形所需的最小操作数,并在所有三个为一组中找出最小值即可。
代码:
#include "cstdio"
#include "string"
#include"iostream"
#include"algorithm"
#include"queue"
#include"stack"
#include"map"
#include"cmath"
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n,a[305];
cin>>n;
int k=0;
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
int m=1000000000;
for(int i=0;i<=n-3;i++)
{
int x;
if(a[i]==a[i+1])
{
if(a[i+1]==a[i+2])
x=0;
else
x=a[i+2]-a[i+1];
}else
{
if(a[i+1]==a[i+2])
x=a[i+1]-a[i];
else
x=a[i+2]-a[i];
}
m=min(m,x);
}
cout<<m<<endl;
}
return 0;
}
B. Bright, Nice, Brilliant
题意:
这个题其实非常简单,只要读懂题目就可以(虽然说有点看不懂)。主要意思就是说,有一个金字塔,每层有与层数对应的房间数(1层一个房间,2层两个房间,3层三个房间......)。中间讲了一大堆废话来误导你,其实就是说,对于每个房间,你可以选择点亮或者不点亮。然后每个房间都有一个亮度值,这个亮度值的计算方法就是,从顶端开始,到达当前房间可以经过的所有房间中,有多少房间是点亮的(包括自己这个房间)。当前有一个“nice”金字塔的定义:每层的每个房间的亮度都是相同的。现在让你找出一个“nice”金字塔,并且每一层最左边的房间点亮数加在一起最大。
题解:
要让最左边房间点亮数加在一起最大,我们可以让最左边的所有房间都点亮,然后你会发现最左边房间的亮度值就是等于层数,这时候我们只要让这一层其他房间的亮度值也是等于层数就OK了。先考虑最右边的房间,到达最右边房间的路只有经过上面每一层的最右边房间,所以要使亮度值等于层数,就只有最右边每个房间都点亮。这时候你会发现其他所有房间都不用点亮,他们的亮度值就已经满足亮度值等于层数了,所以我们只要对每一层,左右输出1中间输出0就可以了。
代码:
#include "cstdio"
#include "string"
#include"iostream"
#include"algorithm"
#include"queue"
#include"stack"
#include"map"
#include"cmath"
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int j=1;j<=n;j++)
{
for(int i=1;i<=j;i++)
{
if(i==1)
cout<<1;
else if(i==j)
cout<<" "<<1;
else
cout<<" "<<0;
}
cout<<endl;
}
cout<<endl;
}
return 0;
}
C. Removing Smallest Multiples
题意:
有一个数组S有n个整数满足a[i]=i(1≤i≤n),你可以选择一个正整数k,然后在S数组中删除k的最小倍数的值,每次操作需要k成本。经过几次操作后(可能是0次)你可以得到另一个数组T。现在给你数组T,问你数组S经过多少次操作可以得到数组T。
题解:
这题当时错了半天,到最后都没a掉,考完看了别人的才a出来,但我感觉我的没有问题。把每个T中每个不存在的数(即T[i]=='0')拿出来单独分析,如果这个数的倍数也不在T中(即T[i*k]=='0')我们就可以认为只需i*k的成本就可以把i、i*2......i*k删除。但此时要注意,如果i*1,i*3不在T中,但是i*2在T中,此时你不能用i*2的成本把i*1,i*3删除,因为你在删除i*1后,i的最小倍数就是i*2,你不能跳过i*2而用i的成本来删除i*3.
代码:
#include "cstdio"
#include "string"
#include"iostream"
#include"algorithm"
#include"queue"
#include"stack"
#include"map"
#include"cmath"
using namespace std;
int a[1000005],vis[1000005];
int main()
{
int t;
cin>>t;
int kk=0;
while(t--)
{
kk++;
int n,p=0;
cin>>n;
string s;
cin>>s;
for(int i=0;i<n;i++)
{
vis[i+1]=0;
if(s[i]=='0')
a[i+1]=0;
else
a[i+1]=1;
}
int sum=0;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j+=i)
{
if(a[j]==1)//若该数在T中则跳出循环
break;
else if(vis[j]==1)//若该数已被前面使用过,则跳过该数
continue;
else
{
sum+=i;
vis[j]=1;
}
}
}
cout<<sum<<endl;
}
return 0;
}
D. Slime Escape
题意:
有n个史莱姆,每个位置为i(1≤i≤n),每个史莱姆有自己的健康值a[i],你当前所在位置为k,史莱姆可以往右或往左走一个位置,每次移动你都要吃掉当前位置上的史莱姆,并获得它的健康值(可能是正也可能是负),吃掉它后,该位置就等于不存在了(如你在6位置,吃掉7后往右再走到达8,此时你的左边应该是5位置,而不是7位置),若你的健康值到达了负值你就直接淘汰了,若你在保证健康值≥0的情况下到达0位置或者n+1位置就算你获胜,问你是否可以获胜。
题解:
考完看大佬代码a的,大佬太强了。先定义i,j代表我们往左和往右走到的位置,我们先往左走,如果往左走可以保证不死并且可以增长健康值,我们就吃掉所走过的这一段的史莱姆,如果保证不死但是健康值不增长我们就跳出,再往右边走,如此反复循环直到i==0或者j==n+1。如果往左走健康值不增长并且往右走健康值也不增长,同时两者都未走到终点,此时就无法获胜了,应当跳出循环(定义一个开关值即可)。
代码:
#include "cstdio"
#include "string"
#include"iostream"
#include"algorithm"
#include"queue"
#include"stack"
#include"map"
#include"cmath"
//#include"bits/stdc++.h"
using namespace std;
int a[200005];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
int i=k-1,j=k+1;
long long sum=a[k],x=0,y=0;
while(i>0&&j<=n)
{
int k1=1;
while(i>0&&sum+a[i]+x>=0)
{
x+=a[i--];
if(x>0)
{
k1=0;
sum+=x;
x=0;
}
}
while(j<=n&&sum+a[j]+y>=0)
{
y+=a[j++];
if(y>0)
{
k1=0;
sum+=y;
y=0;
}
}
if(k1)
break;
}
if(!i||j==n+1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}