poj.org/problem?id=3353
这道题,10%的AC率,看着有点害怕
Total Submissions: 593 | Accepted: 54 |
但是题目读起来并不能难,只是简单得类似罗马数字跟阿拉伯数字的转换;不过仔细阅读却发现题意非常不清晰,没有任何提示说明答案是唯一的,但是题目有没有special judged,所以只能自行断定有歧义的情况应该坐如何选择
1. IVI是不合法的,虽然也可以解释成5,但是5只能是V, 也就是说任何数位都只能用唯一一种表示方法
2. MMMM是不合法的, MMM是合法的,>=4000的字段需要用O
比较有意思的是在我WA了3此后,只好去udebug上碰碰运气,结果还有一样名字的题目,于是乎我就随机生成了几组数据,看看AC的程序是啥样子的,通过对比:
1. 我的代码有个数据未重新初始化的bug,两个大数相加时需要补位的时候,需要两个数位的清零都考虑
2. udebug上的900是用DCD表示的, 而poj改成用CM表示
3. udebug上最多只允许1个O,但是poj允许多个O
所以原题不需要使用大整数,因为最多只有一个O, 那么最大也不过是100*1000*1000,但是poj的版本把题目难度增加了一丢丢,这里为poj点个赞~
实现:
解析字符串 -> 1000进制数组
char eval(char *p) {
st=0;
int v=0, m=100000000, c;
int i=0; while(p[i]) { p[i]=mk[p[i]]; i++; }
for (i=0; p[i]; ) {
if (p[i]=='O') {
if (st==0 && v<=3) return 0;
sk[st++]=v;
v=0; m=1000;
i++;
} else if (p[i]=='M') {
if (m<=1000) return 0;
while(p[i]=='M') { v+=1000; i++; }
m=1000;
} else if (p[i]=='D') {
if (m<=100) return 0;
v+=500;
i++;
// if (p[i]=='C'&&p[i+1]=='D') { i+=2; v+=400; }
if (0) {}
else {
c=0;
while(p[i]=='C') { i++; c++; v+=100; }
if (c>3) return 0;
}
m=100;
} else if (p[i]=='C') {
if (m<=100) return 0;
m=100;
if (p[i+1]=='M') {
// return 0;
v+=900; i+=2;
} else if (p[i+1]=='D') {
v+=400; i+=2;
} else {
c=0; while(p[i]=='C') { i++; c++; v+=100; }
if (c>3) return 0;
}
} else if (p[i]=='L') {
if (m<=10) return 0;
v+=50;
c=0; i++; while(p[i]=='X') { i++; c++; v+=10; }
if (c>3) return 0;
m=10;
} else if (p[i]=='X') {
if (m<=10) return 0;
m=10;
if (p[i+1]=='C') {
v+=90; i+=2;
} else if (p[i+1]=='L') {
v+=40; i+=2;
} else {
c=0; while(p[i]=='X') { i++; c++; v+=10; }
if (c>3) return 0;
}
} else if (p[i]=='V') {
if (m<=1) return 0; m=1;
v+=5;
c=0; i++; while(p[i]=='I') { i++; c++; v+=1; }
if (c>3) return 0;
m=1;
} else if (p[i]=='I') {
if (m<=1) return 0;
m=1;
if (p[i+1]=='X') {
v+=9; i+=2;
} else if (p[i+1]=='V') {
v+=4; i+=2;
} else {
c=0; while(p[i]=='I') { i++; c++; v+=1; }
if (c>3) return 0;
}
} else assert(0);
if (v>=4000) return 0;
}
sk[st++]=v;
// if (st>2) return 0;
return 1;
}
将0-999之间的阿拉伯数字转换为罗马数字
int conv(char *p, int v) {
int c=0;
if (v>=900) {
// p[c++]='D';
// p[c++]='C';
// p[c++]='D';
p[c++]='C';
p[c++]='M';
v-=900;
}
if (v>=500) {
p[c++]='D';
v-=500;
}
if (v>=400) {
p[c++]='C';
p[c++]='D';
v-=400;
}
while(v>=100) {
p[c++]='C';
v-=100;
}
if (v>=90) {
p[c++]='X';
p[c++]='C';
v-=90;
}
if (v>=50) {
p[c++]='L';
v-=50;
}
if (v>=40) {
p[c++]='X';
p[c++]='L';
v-=40;
}
while(v>=10) {
p[c++]='X';
v-=10;
}
if (v>=9) {
p[c++]='I';
p[c++]='X';
v-=9;
}
if (v>=5) {
p[c++]='V';
v-=5;
}
if (v>=4) {
p[c++]='I';
p[c++]='V';
v-=4;
}
while(v>=1) {
p[c++]='I';
v-=1;
}
return c;
}
主函数整体处理
while(scanf("%s", &ib)==1) {
i=0; while(ib[i]&&ib[i]!='+') i++;
if (ib[i]==0) assert(0); ib[i]=0;
if (eval(ib)==0) { printf("INVALID\n"); continue;}
c1=0; while(st) { --st; v1[c1++]=sk[st]; }
if (c1==1&&v1[0]==0) assert(0);
if (eval(ib+i+1)==0) { printf("INVALID\n"); continue;}
c2=0; while(st) { --st; v2[c2++]=sk[st]; }
if (c2==1&&v2[0]==0) assert(0);
mc=c1; if (mc<c2) mc=c2;
for (i=c1; i<mc; i++) v1[i]=0;
for (i=c2; i<mc; i++) v2[i]=0;
v=0; for (i=0; i<mc; i++) { v=v1[i]+v2[i]+v; v1[i]=v%1000; v/=1000; }
while(v) { v1[mc++]=v%1000; v/=1000; }
k=0; for (i=mc-1; i>=0; i--) {
v=v1[i]; if (i==mc-1&&i>0&&v<=3) {
while(v) { ob[k++]='M'; v--; }
} else {
k+=conv(ob+k, v);
if (i) ob[k++]='O';
}
}
ob[k++]='=';
for (i=mc-1; i>=0; i--) {
v=v1[i]; st=0; for (j=0; j<3; j++) sk[j]=0;
while(v) { sk[st++]=v%10; v/=10; } if (st==0) st=1;
if (i==mc-1) {
while(st) { st--; ob[k++]=sk[st]+'0'; }
} else {
for (j=2; j>=0; j--) ob[k++]=sk[j]+'0';
}
}
ob[k++]=0;
printf("%s\n", ob);
}
题不难,就是题意模糊,但是终究可以通过试错来定位到题意,算是很恶心的地方
2730