@xingxing
2016-12-08T22:49:49.000000Z
字数 7574
阅读 926
题解
[题目][A]
Design Tutorial: Learn from Math
题目大意:
给定一个n(12<=n<=10^6),输出符合条件的两个合数x,y,要求:x+y=n。
解题思路:
要满足x+y=n,即一个数x大于等于n/2,一个数y小于等于n/2,列举x和y,然后分别对x,y判断是否为合数。
时间复杂度O(n√n),空间复杂度(1)。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
int solve(int m)
{
int i;
for(i = 2;i <= (int)sqrt(m);i++)
{
if(m % i == 0)
{
return 1;
}
}
return 0;
}
int main()
{
int n;
int i;
while(scanf("%d",&n) != EOF)
{
for(i = n/2;i > 1;i--)
{
if(solve(i) && solve(n-i))
{
printf("%d %d\n",i,n-i);
break;
}
}
}
return 0;
}
[题目][B]
Design Tutorial: Learn from Life
题目大意:
给出乘客数n和电梯一次性最大载客量k(1<=n,k<=2000),以及n个乘客到达的目标楼层fi,(2<=f[i]<=2000),电梯用1s上一层楼,人数载量与电梯运行时间无关。初始时,人们都在第一层,求出最少时间能把所有人都运完,并且电梯又回到一楼。
解题思路:
电梯初始时在一楼,最后也要回到一楼,即每次运完乘客都要回到一楼继续运。而无论如何,最高楼层的人是要通过电梯过去的,所以当前要用的最少时间要以最高楼层的人到达的楼数来决定。所以尽可能把高楼层的乘客运完,即对目标楼层数按降序排序,从大到小,每次不超过k的限度运。
时间复杂度O(n),空间复杂度O(1)。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
int f[2016];
int main()
{
int n,k;
int i;
int ans;
while(scanf("%d %d",&n,&k) != EOF)
{
ans = 0;
for(i = 0;i < n;i++)
{
scanf("%d",&f[i]);
}
sort(f,f+n);
if(n >= k)
{
for(i = n-1; i >= 0 && i+1 >= k;i -= k)
{
ans += 2*(f[i] - 1);
}
if(i+1 < k && i >= 0)
{
ans += (f[i]-1)*2;
}
}
else
{
ans += 2*(f[n-1]-1);
}
printf("%d\n",ans);
}
return 0;
}
[题目][C]
Design Tutorial: Make It Nondeterministic
题目大意:
给出n个人(1<=n<=10^5)的名和姓,其中每个人的姓fi和名si由只含小写字母的字符串组成(1<=|fi|,|si|<=50),并且这2n个姓、名互不相同。接着给出排列好的n个数据pi(1<=pi<=n)。判断这n个人的姓或名能否按字典序以所给出的数据列排序。
解题思路:
贪心。要尽可能满足所给出数据列的字典序,排在前面的人,应该选较小的名或姓作为它的handle。即,选择p1姓或名的最小字典序的,作为h1(p1的handle),然后每次判断一下后一个pi+1较大的字符串是否大于pi的字符串,尽可能选择pi+1较小的字符串作为hi+1,把满足要求的可能性扩大到最大。当某一时刻,hi比pi+1最小的字符串还大时,此时不能得到与数据列相吻合的字典序。
时间复杂度O(n),空间复杂度O(1)。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int maxx = 123456;
typedef struct name
{
char f[60],s[60];
int flag;
}person;
person a[maxx];
int main()
{
//freopen("in.txt","r",stdin);
int n;
int i;
int num;
char temp[60];
int flag1 = 0;
scanf("%d",&n);
for(i = 0;i < n;i++)
{
getchar();
scanf("%s",a[i].f);
getchar();
scanf("%s",a[i].s);
if(strcmp(a[i].f,a[i].s) >= 0) a[i].flag = 1;
else a[i].flag = 0;
}
for(i = 0;i < n;i++)
{
scanf("%d",&num);
if(i == 0 && a[num-1].flag == 1)
{
strcpy(temp,a[num-1].s);
}
else if(i == 0 && a[num-1].flag == 0)
strcpy(temp,a[num-1].f);
if(i != 0)
{
if(a[num-1].flag == 1)
{
if(strcmp(temp,a[num-1].f) >= 0)
flag1 = 1;
else
{
if(strcmp(temp,a[num-1].s) >= 0)
strcpy(temp,a[num-1].f);
else strcpy(temp,a[num-1].s);
}
}
else
{
if(strcmp(temp,a[num-1].s) >= 0) flag1 = 1;
else
{
if(strcmp(temp,a[num-1].f) >= 0)
strcpy(temp,a[num-1].s);
else strcpy(temp,a[num-1].f);
}
}
}
}
if(flag1 == 1) printf("NO\n");
else printf("YES\n");
return 0;
}
[题目][E]
MUH and Sticks
题目大意:
给出6个数li(1<=li<=9),判断满足以下哪个条件:
(1)其中4个数相同,另外2个数一大一小,这两个数和另外的4个数没有绝对的大小关系时,输出Bear;
(2)4个数相同,另外2个数相等,这两个数和另外的4个数没有绝对的大小关系,此时输出Elephant;
(3)其余情况输出Alien.
解题思路:
因为6个数中,只有一组4个数相同,不会再有其他4个数相同的情况,所以先选出相同的四个数,再来判断剩下的2个数之间的关系。两个数只有两种关系,要么相等,要么不等,即在有4个数相同的前提下,分别为1和2的情况。当无法选出4个相同数时,此时为情况3。把i数字读入后,将个数计入ai。
时间复杂度O(1),空间复杂度O(1)。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int a[20];
int main()
{
int i;
int len;
int flag1,flag2;
flag1 = 0,flag2 = 0;
for(i = 0;i < 6;i++)
{
scanf("%d",&len);
a[len]++;
}
for(i = 1; i <= 9; i++)
{
if(a[i] == 4)
{
flag1 = 1;
}
if(a[i] == 2)
{
flag2 = 1;
}
if(a[i] == 6)
{
flag1 = 1;
flag2 = 1;
}
if(a[i] == 5)
{
flag1 = 1;
flag2 = 0;
}
}
if(flag1 && flag2)
printf("Elephant\n");
else if(flag1 && flag2 == 0)
printf("Bear\n");
else printf("Alien\n");
return 0;
}
[题目][F]
题目大意:
给出n(1<=n<=2000)个任务的难度hi(1<=hi<=2000).将n个任务按难度排序输出,当有相同难度的任务时,可以交换序号从而产生难度相同,而序列不同的几种方案。输出其中3种方案的序列,若没有3个则输出NO。
解题思路:
因为要输出3组不同的序列,即可以只考虑(1)同一个难度有3个及以上的数量;或者(2)2个相同难度的任务组数为2的,有2组及以上。把难度i的任务存入a[i]数组中,并保存总共的该难度的任务数量以及对应的序号。然后遍历这个结构体数组,看是否有3个及以上的难度任务,和2组以上2个某个难度的任务。如果符合情况1,则将大于或等于3的难度值的序号,取其中三个,排列输出三种,其余该难度下多的直接输出,其他的序号直接输出。整体输出保持不递减的顺序,同时注意输出空格的格式,如果为输出的第一个数,则数字前没有空格,否则每个数字前都有一个空格。如果符合情况2,则将其他n-2个难度值的任务序号,按难度值递增输出,当到达记录的两组难度值时,进行以下处理,将前一个难度值的2个任务序号排序,现在既有2组,然后后一个难度值的任务序号,只要在第三组改变一下顺序,就总共有3组输出。
时间复杂度O(n),空间复杂度O(1)。
AC 代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef struct task
{
int pa[2016];
int num;
}diff;
diff a[2016];
int h3,h1,h2;
int main()
{
int n;
int i,j;
int temp;
int len;
int flag1,flag2;
int cnt;
int order,zu;
while(scanf("%d",&n) != EOF)
{
for(i = 1;i <= 2000;i++)
{
a[i].num = 0;
}
for(i = 1;i <= n;i++)
{
scanf("%d",&temp);
len = a[temp].num;
a[temp].pa[len] = i;
a[temp].num++;
}
flag1 = 0,flag2 = 0;
cnt = 0;
h1 = 0,h2 = 0;
for(i = 1;i <= 2000;i++)
{
if(a[i].num >= 3)
{
flag1 = 1;
h3 = i;
break;
}
if(a[i].num == 2 && h1 == 0)
{
cnt++;
h1 = i;
}
else if(a[i].num == 2 && h2 == 0)
{
cnt++;
h2 = i;
}
if(cnt == 2)
{
flag2 = 1;
break;
}
}
order = 0,zu = 0;
if(flag1)
{
printf("YES\n");
while(zu <= 2)
{
order = 0;
for(i = 1; i <= 2000; i++)
{
if(i == h3)
{
if(order == 0)
{
if(zu == 0)
{
printf("%d %d %d",a[i].pa[0],a[i].pa[1],a[i].pa[2]);
}
if(zu == 1)
{
printf("%d %d %d",a[i].pa[1],a[i].pa[0],a[i].pa[2]);
}
if(zu == 2)
{
printf("%d %d %d",a[i].pa[0],a[i].pa[2],a[i].pa[1]);
}
order += 3;
for(j = 3; j < a[i].num; j++)
{
printf(" %d",a[i].pa[j]);
order++;
}
}
else
{
if(zu == 0)
{
printf(" %d %d %d",a[i].pa[0],a[i].pa[1],a[i].pa[2]);
}
if(zu == 1)
{
printf(" %d %d %d",a[i].pa[1],a[i].pa[0],a[i].pa[2]);
}
if(zu == 2)
{
printf(" %d %d %d",a[i].pa[0],a[i].pa[2],a[i].pa[1]);
}
order += 3;
for(j = 3; j < a[i].num; j++)
{
printf(" %d",a[i].pa[j]);
order++;
}
}
}
else
{
for(j = 0; j < a[i].num; j++)
{
if(order == 0)
{
printf("%d",a[i].pa[j]);
order++;
}
else
{
printf(" %d",a[i].pa[j]);
order++;
}
}
}
}
zu++;
printf("\n");
}
}
else if(flag2)
{
printf("YES\n");
while(zu <= 2)
{
order = 0;
for(i = 1; i <= 2000; i++)
{
if(i == h1)
{
if(order == 0)
{
if(zu == 0) printf("%d %d",a[i].pa[0],a[i].pa[1]);
if(zu == 1) printf("%d %d",a[i].pa[0],a[i].pa[1]);
if(zu == 2) printf("%d %d",a[i].pa[1],a[i].pa[0]);
order += 2;
}
else
{
if(zu == 0) printf(" %d %d",a[i].pa[0],a[i].pa[1]);
if(zu == 1) printf(" %d %d",a[i].pa[0],a[i].pa[1]);
if(zu == 2) printf(" %d %d",a[i].pa[1],a[i].pa[0]);
order += 2;
}
}
else if(i == h2)
{
if(order == 0)
{
if(zu == 0) printf("%d %d",a[i].pa[0],a[i].pa[1]);
if(zu == 1) printf("%d %d",a[i].pa[1],a[i].pa[0]);
if(zu == 2) printf("%d %d",a[i].pa[1],a[i].pa[0]);
order += 2;
}
else
{
if(zu == 0) printf(" %d %d",a[i].pa[0],a[i].pa[1]);
if(zu == 1) printf(" %d %d",a[i].pa[1],a[i].pa[0]);
if(zu == 2) printf(" %d %d",a[i].pa[1],a[i].pa[0]);
order += 2;
}
}
else
{
for(j = 0;j < a[i].num;j++)
{
if(order == 0)
{
printf("%d",a[i].pa[j]);
order++;
}
else
{
printf(" %d",a[i].pa[j]);
order++;
}
}
}
}
zu++;
printf("\n");
}
}
else printf("NO\n");
}
return 0;
}
[题目][I]
George and Accommodation
题目大意:
给出n(1<=n<=100)个房间的已住人数pi和房间容量qi(0<=pi<=qi<=100),求qi-pi>=2个i的个数。
解题思路:
读入pi和qi,然后判断两者差值,若大于或等于2则结果加1.
时间复杂度O(n),空间复杂度O(1)。
AC 代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int main()
{
int n;
int ans = 0;
int p,q;
scanf("%d",&n);
while(n--)
{
scanf("%d%d",&p,&q);
if(q-p >= 2) ans++;
}
printf("%d\n",ans);
return 0;
}
[题目][J]
Fedor and New Game
题目大意:
有n个soldiers编号从0到n-1,m+1个player,编号从1到m+1.对于第m+1个player前的每个player的army数值xi进行判断,如果army的表达数xi与第m+1个player的二进制表达中"1"不同的地方不超过k那么第m+1个player的朋友数加1.(1<=k<=n<=20,1<=m<=1000,1<=xi<=2^n-1)
解题思路:
对前m个数的二进制"1"的位置与最后一个数的二进制"1"的位置进行判断,若位置不同数不超过k,则结果加1.把m+1个数转成二进制,然后把每一位数值保存在数组中,并且将数组中第一位拿来保存该数值转成二进制数后的位数。然后分别对前m个二进制位与最后一个数的二进制位进行比较,统计不同位的个数。
时间复杂度O(n),空间复杂度O(1)。
AC 代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int n,m,k;
int a[1010][30];
int main()
{
int i,j;
int temp;
int ans = 0;
int cnt = 0;
scanf("%d%d%d",&n,&m,&k);
for(i = 0; i < m+1; i++)
{
scanf("%d",&temp);
j = 1;
while(temp != 0)
{
a[i][j] = temp % 2;
temp = temp / 2;
j++;
}
a[i][0] = j;
}
for(i = 0;i < m;i++)
{
cnt = 0;
for(j = 1;j <= a[i][0] && j <= a[m][0];j++)
{
if(a[i][j] != a[m][j]) cnt++;
}
if(j <= a[i][0])
{
for(;j <= a[i][0];j++)
{
if(a[i][j] == 1) cnt++;
}
}
else
{
for(;j <= a[m][0];j++)
{
if(a[m][j] == 1) cnt++;
}
}
if(cnt <= k) ans++;
}
printf("%d\n",ans);
return 0;
}
[题目][M]
Cheap Travel
题目大意:
进行n次乘车,每次花a元,或者可以选择用b元一次性买好m次乘车的票。(1<=n,m,a,b<=1000),求出要乘n次车最少花的钱。
解题思路:
判断b元m次车票的单价,与a进行比较,选择叫便宜的方式。如果m次车票更好,那么买n/m张m次车票,然后再看剩下的车票用a元票买便宜还是m次车票便宜。
时间复杂度O(1),空间复杂度O(1)。
AC 代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int main()
{
int n,m,a,b;
int num;
double x;
int sum = 0;
scanf("%d%d%d%d",&n,&m,&a,&b);
x = (double)b/m;
if(x < (double)a)
{
num = n / m;
sum = num * b;
sum += min(b,a*(n % m));
}
else sum = n*a;
printf("%d\n",sum);
return 0;
}