POJ3353 1000进制大整数|水题|题意揣摩

poj.org/problem?id=3353

这道题,10%的AC率,看着有点害怕

Total Submissions: 593Accepted: 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值