为什么ACM赛变成了个人赛……
NO.1
BBQ Easy
题目不给给出处吧:AtCoder 1979
思路
这道题有一个很明显的贪心,由于两串肉串的容肉数是由最短的棒决定的,所以必须保证两根木棒的长度差最小,所以只需将其排序,然后取短的累加即可。
代码如下
#include<bits/stdc++.h>
using namespace std;
int a[1001];
long long s=0;
int main()
{
int n;
cin>>n;
for(int i=1;i<=2*n;i++)
cin>>a[i];
sort(a+1,a+2*n+1);
for(int i=1;i<=2*n;i+=2)
s+=a[i];
cout<<s<<endl;
return 0;
}
(这题看着简单,我理解题目理解了半年……)
NO.2
Memory and Trident
CodeForces 712B
思路
首先必须明确,走奇数步是不可能回到原点的,然后,由于要回到原点,所以向两个方向相反的方向走的步数必须相同,两方向的步数差相加就是最少改变的步数的两倍。
代码如下
#include<bits/stdc++.h>
using namespace std;
int l=0,r=0,u=0,d=0,sum=0,x,s1;
int main()
{
string s;
cin>>s;
s1=s.size();
if(s1%2!=0)//走奇数步一定不可能回到原点
{
cout<<-1<<endl;
return 0;
}
x=s1/4;
for(int i=0;i<=s1-1;i++)//统计向各个方向走的步数
{
if(s[i]=='L') l++;
if(s[i]=='R') r++;
if(s[i]=='U') u++;
if(s[i]=='D') d++;
}
//保证向左和向右走的步数相同,向上和向下走的步数相同
if(l!=r)
{
sum+=abs(l-r);
}
if(u!=d)
{
sum+=abs(u-d);
}
cout<<sum/2<<endl;//左右的步数差相加是应该改变的两倍
return 0;
}
由于没有判断清楚能走回原地的步数,导致我交了好多次都没有AC,下面的一半代码倒是改了半天
NO.3
Tea Party
CodeForces 808C
思路
首先我们应该保证每杯水都倒满一半,满足第一个条件,如果倒完后所剩的水为负,那么说明给定的水无法满足第一个条件,输出-1。若还有剩余,则可利用循环加水,需满足体积大的杯子装水多所以从体积大的杯子开始加,每次都加满,如果所剩的水无法加满,那么将水都倒入这个杯中,结束循环。最后再按照原输入顺序输出即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[1010],b[1010],s=0,k;
struct bbb
{
int a,b,c;
}bb[1010];
bool cmp(bbb x,bbb y)
{
return x.a>y.a;
}
bool mycmp(bbb g,bbb h)
{
return g.c<h.c;
}
int main()
{
int n,x;
cin>>n>>x;
for(int i=1;i<=n;i++)//先满足前两个条件,给每个杯子加一半的水
{
cin>>bb[i].a;
if(bb[i].a%2==0)
{
bb[i].b=bb[i].a/2;
x-=bb[i].b;
}
else
{
bb[i].b=bb[i].a/2+1;
x-=bb[i].b;
}
bb[i].c=i;
}
sort(bb+1,bb+n+1,cmp);//按照杯子体积排序
if(x<0)//如果剩下的水是负数,说明无法满足每个杯子倒一半体积的水的条件,输出-1
{
cout<<-1<<endl;
return 0;
}
if(x>0)
{
for(int i=1;i<=n;i++)
{
x-=bb[i].a-bb[i].b;//将体积大的杯子倒满水
bb[i].b=bb[i].a;//此时杯子里的水是水的体积
if(x<0)//若小于0,说明无法倒满,现在水的体积即为一半的体积加所剩的水
{
bb[i].b+=x;
x=0;
break;//无水可倒,跳出循环
}
}
}
sort(bb+1,bb+n+1,mycmp);//将被子恢复到开始的顺序输出
for(int i=1;i<=n-1;i++)
cout<<bb[i].b<<' ';
cout<<bb[n].b<<endl;
return 0;
}
NO.4
Buns
思路:
多重背包模版题,但是我同桌用资源分配AC了,将所有的物品转化为最多可用n[i]个,每个都有v[i]的价值,w[i]的花费,然后套模版即可(老师分析时这样讲的,然而我好像并没有深刻理解)
本题不附代码
NO.5
Appleman and Toastman
思路:
递推题。经递推可以得出,最大的价值是每次都去掉最小的那个数,那么也不难推出,先将其从大到小进行排序,从最大值开始求前缀和,每一次最大值只累加一次,而其余前缀都会累加两次,此时为最优解。
代码如下:
#include<bits/stdc++.h>
using namespace std;
long long a[301010]={},sum=0,b[301010]={};
bool cmp(int x,int y)//从大到小排序
{
return x>y;
}
int main()
{
long long n;
cin>>n;
for(long long i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];//第一次累加全部
}
b[0]=0;
sort(a+1,a+n+1,cmp);//将a数组进行排序,方便统计由大到小的前缀和
for(long long i=1;i<=n;i++)
b[i]=a[i]+b[i-1];//求前缀和
for(long long i=2;i<=n;i++)
sum+=b[i];//除唯一一个最大值只累加一次,其余数都累加两次(前面已经进行一次累加)
cout<<sum<<endl;
return 0;
}
注意数据范围,因为这个修改了思路,然而一次又一次wa掉
At last
Lakes in Berland
思路:
dfs搜索出湖泊的大小并用一个点存在结构体中,最后又num[0]个湖泊,再按湖泊大小排序需要填的湖泊是前n-k个,然后dfs得出结果
(只有分析,没有代码)
本次比赛,得出以下结论:
1.考试时应该看清题目,理解透然后再做。
2.考虑方面要充分,不能少判断或错判断
3.数据范围坑死人啊~
4.递归递推是基础