本来这一周的练习是杭电的新生赛,但是很多同学没有及时的注册周赛,所以才有了这一场补充周赛,题目连接这里:swpu-acm集训队补充周赛,所以我就不把题目写出来了,话不多说,上题解:
A:题意无比明确啊,给你a,b,s三个数,求是否恰好用给定的s步内从(0,0)到(a,b),判断一下就好,从(0,0)到(a,b)最少需要abs(a-0)+abs(b-0)步,如果s小于这个值,肯定到不了啊,如果大于等于的话,判一下两者之前的差值是不是偶数啊,为什么要是偶数呢?因为我可以先花abs(a-0)+abs(b-0)步到(a,b),然后往任意一个方向走一步,再回来,2步,一直循环这样,只要为2的倍数(包括0,刚好到),一定可以回来,下面是代码
#include
using namespace std;
int main(){
int a,b,s;
while(~scanf("%d%d%d",&a,&b,&s)){
int x = abs(a-0);
int y = abs(b-0);
if(s < x+y) printf("No\n");
else{
if(abs(s-x-y)%2 == 0) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
B:B题应该是比A题更容易思考到的,给你n个价值,问最少取多少个价值之和大于总价值的一半。从大到小排一下序,先存一个值的一半(偶数除2加一,因为要大于一半,奇数也是除2加一),然后在一个for里面累加的时候判断就行了
#include
using namespace std;
typedef long long ll;
int cmp(int a,int b){
return a > b;
}
int main(){
int n,a[105],sum = 0;
scanf("%d",&n);
for(int i = 0;i < n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
sum = sum/2+1;
int ans = 0;
sort(a,a+n,cmp);
for(int i = 0;i < n;i++){
ans += a[i];
if(ans >= sum) {printf("%d\n",i+1);break;}
}
return 0;
}
C:给你n个学校的人数和公车最大载人数,判断最少需要几辆公车可以把所有的人载完,但是每个学校的同学要么全上,要么全不上,加的时候判断就行,因为每个学校的人数一定不大于公车最大载人数,所以,每个公车至少一个学校,那么直接把离当前最近的学校的同学全部拉上车,然后判断是否超载,是,则这一个学校的同学全部到另外的车上去,公车数量加一
#include
using namespace std;
int main(){
int n,m,a[105];
while(~scanf("%d%d",&n,&m)){
for(int i = 0;i < n;i++)
scanf("%d",&a[i]);
int sum = 0,ans = 1;
for(int i = 0;i < n;i++){
sum += a[i];
if(sum > m) ans++,sum = a[i];
}
printf("%d\n",ans);
}
return 0;
}
D:本场防AK题?大模拟啊,因为猫和老鼠的移动方向是一样的,所以只需要写一个移动的函数,然后模拟逃亡的状态就行了,注意的是有可能猫永远抓不到老鼠,所以当你的时间超过某一个值的时候其实已经形成了一个循环,所以要稍微判断一下防止循环超时,代码量略大,但是其实只是无脑模拟而已,水题,具体情况看代码吧
#include
int main()
{
int MD,CD,MX,MY,CX,CY;
int t;
long time;
char map[10][11];
int i,j,k;
scanf("%d",&t);
while(t--)
{
MD = 0;
CD = 0;
time = 0;
for (i=0; i<10; i++)
scanf("%s",map[i]);
for (i=0; i<10; i++)
{
for (j=0; j<10; j++)
{
if (map[i][j] == 'c')
{
CX = i;
CY = j;
}
if (map[i][j] == 'm')
{
MX = i;
MY = j;
}
}
}
while (1)
{
if (MX == CX && MY == CY)
break;
switch (CD)
{
case 0:
if (CX-1<0||map[CX-1][CY] == '*')//上
{
CD++;
}
else
{
CX--;
}
break;
case 1:
if (CY+1 == 10||map[CX][CY+1] == '*')//右
{
CD++;
}
else
{
CY++;
}
break;
case 2:
if (CX+1 == 10||map[CX+1][CY] == '*')//下
{
CD++;
}
else
{
CX++;
}
break;
case 3:
if (CY-1<0||map[CX][CY-1] == '*')//左
{
CD=0;
}
else
{
CY--;
}
break;
}
switch (MD)
{
case 0:
if (MX-1<0||map[MX-1][MY] == '*')//上
{
MD++;
}
else
{
MX--;
}
break;
case 1:
if (MY+1 == 10||map[MX][MY+1] == '*')//右
{
MD++;
}
else
{
MY++;
}
break;
case 2:
if (MX+1 == 10||map[MX+1][MY] == '*')//下
{
MD++;
}
else
{
MX++;
}
break;
case 3:
if (MY-1<0||map[MX][MY-1] == '*')//左
{
MD=0;
}
else
{
MY--;
}
break;
}
time++;
if(time>100000)break;
}
if(time>100000) printf("0\n");
else
printf("%d\n",time);
}
return 0;
}
E:给你n个数,判断有多少对数之和小于s,直接暴力写两个循环复杂度是2w*2w,4亿左右,肯定是不可取的,稍微优化一下,先从小到大排个序,然后一遍i,j从i+1开始循环,这样保证每次选的两个数不会重复,当a[i]+a[j] > s之后直接跳出循环,因为是从小到大排序,a[i]+a[j] > s,a[j+1] > a[j],a[i]+a[j+1] > s,所以后面的数都不用考虑,在i的循环里面当a[i]+a[i+1] > s时一定直接跳出,因为i到后面最小的和都是a[i]+a[i+1],因此不予考虑后面,代码如下:
#include
#include
#include
#include
using namespace std;
int n,s,a[20005];
int main(){
while(~scanf("%d%d",&n,&s)){
memset(a,0,sizeof(a));
for(int i = 0;i < n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int count = 0;
for(int i = 0;i < n-1;i++){
if(a[i]+ a[i+1] > s) break;
for(int j = i+1;j < n;j++){
if(a[i] + a[j] > s) break;
else count++;
}
}
printf("%d\n",count);
}
return 0;
}
集训队的各位还要好好加油啊,AK1位,大二的hhz,4题的6位。大家加油