昨天下午TOJ上又开了个小比赛,前面几个题目比较简单,后面的就因为时间问题看都没有看,不过看做的人数,估计会有点难度,把自己做的几个题目作个小结。
TOJ 3039 Judging Olympia
给出六个数去掉最小跟最大的两个然后求平均值,注意一下输出格式就好了。
#include <iostream>
#include <algorithm>
using namespace std;
int score[6];
int main()
{
while(true){
for(int i = 0; i < 6; i++)
cin>>score[i];
if(!score[0] && !score[1] && !score[2] && !score[3] && !score[4] && !score[5])
break;
sort(score, score+6);
int sum = 0;
for(int i = 1; i < 5; i++)
sum += score[i];
cout<<sum/4.0<<endl;
}
return 0;
}
TOJ 3040 Hide That Number
看题目可能会有点小难度,但仔细一想,也是蛮简单的问题。有很多种做法,可以在前面试加从1到9的数字,然后判断看能不能被11整除,可以的话,就用字符串模拟,把商算出来;最简单地就是将输入的最后一位作为输出字符串的最后一位,然后不断地用输入字符串以处理的前一位的值减去输出字符串的刚得到的位的结果,直到输入字符串中剩最后一位,再单独处理一下,如果结果中的第一位为'0',则说明是"IMPOSSIBLE"。
#include <iostream>
#include <string>
using namespace std;
char instr[1000001], outstr[1000001];
int main()
{
int turn = 1;
while(gets(instr)){
if(!strcmp(instr, "0"))
break;
if(strlen(instr) == 1){
printf("%d. %s\n", turn++, instr);
continue;
}
int tag = strlen(instr)-1;
outstr[tag+1] = '\0';
outstr[tag] = instr[tag];
char pre = outstr[tag];
tag--;
while(tag > 0){
if(instr[tag] < pre){
instr[tag] += 10;
instr[tag-1]--;
}
outstr[tag] = instr[tag]-pre+'0';
pre = outstr[tag];
tag--;
}
if(instr[0] < pre)
instr[0] += 10;
outstr[0] = instr[0]-pre+'0';
if(outstr[0] == '0')
printf("%d. IMPOSSIBLE\n", turn++);
else
printf("%d. %s\n", turn++, outstr);
}
return 0;
}
TOJ 3041 Rotating Rings
这个可能是前面五个题目中难度最大的一个吧,我是无奈之下Debug了两次才整出来的。题目应该可以看成是一个匹配的问题,大致地做法就是把正方形看成是由外到内的一个正方形组成,然后一层一层地进行匹配,每一层又可以按四条边分成四次匹配过程。假如现在是匹配最外面一层,那么就可以先确定这一层左上角的那个元素,然后依次可以匹配它右边的处在该行的所有元素,再最后一列,最后一行,第一列,如果在这个过程中遇到不能匹配的就直接退出,输出"NO"。
#include <iostream>
using namespace std;
int input[1001][1001], n, start, end;
int next(int row, int col)
{
int cur = input[row][col];
if(cur%n == start){//the current is in the start col
if(cur/n == start-1)//the current is in the left-up
return cur+1;
else
return cur-n;
}else if(cur/n == start-1){//the current is in the start row
if((cur%n == end) || (cur%n == 0))//the current is in the right-up
return cur+n;
else
return cur+1;
}else if((cur%n == end) || (cur%n == 0)){//the current is in the end col
if((cur-1)/n == end-1)//the current is in the right-down
return cur-1;
else
return cur+n;
}else if((cur-1)/n == end-1){//the current is in the end row
if(cur%n == start)//the current is in the left-down
return cur-n;
else
return cur-1;
}
}
bool compare(int k)
{
end = n-k+1, start = k;
for(int i = k; i < end; i++){
if(input[k][i+1] != next(k,i))
return false;
}
for(int i = k; i < end; i++){
if(input[i+1][end] != next(i,end))
return false;
}
for(int i = end; i > k; i--){
if(input[end][i-1] != next(end,i))
return false;
}
for(int i = end; i > k; i--){
if(input[i-1][k] != next(i,k))
return false;
}
return true;
}
int main()
{
int turn = 1;
while(cin>>n){
if(!n)
break;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d", &input[i][j]);
bool ans = true;
for(int i = 1; i <= n/2; i++){
if(!compare(i)){
ans = false;
break;
}
}
if((n%2 == 1) && ans){
if(input[n/2+1][n/2+1] != (n*n)/2+1)
ans = false;
}
if(ans)
printf("%d. YES\n", turn++);
else
printf("%d. NO\n", turn++);
}
return 0;
}
TOJ 3042 A Tale from the Dark Side of The Moon
我觉得这个题目是除了第一个之外最简单地一个,就是一个简单地字符串处理。不过想不通的是我最后做这个的时候竟然发现都只有蛮少的人在做,而且通过率比较低。这个题目告诉我地唯一一件事就是小心、小心、再小心。
#include <iostream>
#include <string>
using namespace std;
char instr[81], outstr[81];
int main()
{
while(gets(instr)){
int len = strlen(instr);
int i = 0, tag = 0;
while(i < len){
if(instr[i] == 'd'){
if((i < len-1) && (instr[i+1] == 'd')){
outstr[tag++] = 'p';
i += 2;
}else{
outstr[tag++] = 'd';
i++;
}
}else if(instr[i] == 'e'){
if((i < len-1) && (instr[i+1] == 'i')){
if((i > 0) && (instr[i-1] == 'c')){
outstr[tag++] = 'e';
outstr[tag++] = 'i';
i += 2;
}else{
outstr[tag++] = 'i'; outstr[tag++] = 'e';
i += 2;
}
}else{
outstr[tag++] = 'e';
i++;
}
}else if(instr[i] == 'p'){
if((i < len-3) && (instr[i+1] == 'i') && (instr[i+2] == 'n') && (instr[i+3] == 'k')){
outstr[tag++] = 'f'; outstr[tag++] = 'l'; outstr[tag++] = 'o';
outstr[tag++] = 'y'; outstr[tag++] = 'd';
i += 4;
}else{
outstr[tag++] = 'p';
i++;
}
}else if((instr[i] >= 'a') && (instr[i] <= 'z')){
outstr[tag++] = instr[i];
i++;
}else if(instr[i] == 'E'){
if((i <= len-3) && (instr[i+1] == 'O') && (instr[i+2] == 'F')){
outstr[tag] = '\0';
printf("%s", outstr);
return 0;
}
i++;
}
else if(instr[i] == ' '){
outstr[tag++] = ' ';
i++;
}
else
i++;
}
outstr[tag] = '\0';
printf("%s\n", outstr);
}
return 0;
}
TOJ 3043 Fermat's Chirstmas Theorem
做这个题目的时候我都快觉得这个题目有点BT了,因为那数据跟时间实在有点……都不知道该怎么说了。但后面经过一系列地优化之后,竟然让程序飞快地跑了起来。本来想打表把所有的素数全部保存在数组中的,后来发现光是这些素数就有500多K了。没办法,进行预处理,不过这也是要时间的。本来是用筛选法把到达各个数为止的素数地个数计算出来保存在数组中,但后面发现还有更简单地办法,就是那个6*N+1跟6*N+5,所以采取了后者。再判断一个数能否分成两个数地平方的和,我采用了逆向地方法,从1到sqrt(n+1)/2的两个数的平方的和表示出来,也就是所有符合条件的数,再循环一次进行统计,这样可以节约很多时间。
#include <iostream>
#include <cmath>
using namespace std;
const int MAX = 1000001;
bool flag[MAX], flag2[MAX];
int prim[MAX], fermat[MAX];
void initPrim()
{
flag[0] = flag[1] = true;
int sum = 0;
for(int i = 2; i < MAX; i++){
if(!flag[i]){
for(int j = 2*i; j < MAX; j+=i)
flag[j] = true;
sum++;
}
prim[i] = sum;
}
}
void initFermat()
{
int tmp = (int)sqrt((MAX+1)/2.0);
flag2[2] = true;
for(int i = 1; i <= tmp; i++){
int j = i, tmp = i*i+j*j;
while(tmp <= MAX){
if(((tmp-1)%4 == 0) && (!flag[tmp]))
flag2[tmp] = true;
j++;
tmp = i*i+j*j;
}
}
int sum = 0;
for(int i = 1; i < MAX; i++){
if(flag2[i])
sum++;
fermat[i] = sum;
}
}
int main()
{
int l, u, x, y;
initPrim();
initFermat();
while(scanf("%d%d", &l, &u) != EOF){
if((l == -1) && (u == -1))
break;
printf("%d %d ", l, u);
if((l <= 0) && (u < 0)){
u = 0;
l = 1;
}else if(l <= 0){
l = 1;
}
x = prim[u]-prim[l-1];
y = fermat[u]-fermat[l-1];
printf("%d %d\n", x,y);
}
return 0;
}
TOJ 2469 Friends
题目的意思是这样的:N个人要住旅馆,然后给出M个关系,关系为两个数字a和b,表示编号为a的人和编号为b的是朋友,然后他们就可以住在一间房 里,朋友关系可以传递,也就是如果a和b是朋友,b和c是朋友,那么a和c也是朋友。要求的是需要订的最少的房间。题目有个前提,就是每间房子都足够大。
这个题目比较简单,而我专门为它写这个解题报告是因为我在做这个题目的时候犯了一个错误,找了很久都没有找出来,写出来是为了让自己更好地记住,避免下次再犯同样的错误。
大概的思路是这样:用一个数组来表示各个人的编号,也就是原先默认
评论