网教10. 琪露诺的完美算数教室——⑨的统计I

来源:互联网 发布:蓝桥物流软件 编辑:程序博客网 时间:2024/05/21 22:53

众所周知,琪露诺(チルノ,Cirno)是幻想郷 (げんそうきょう)中首屈一指的天才,可以说⑨就是她的代名词。

然而如今,她遇到了一个和⑨有关的难题。你能帮助她么?

题目是这样的,给出两个数 a 和 b (0 <= a <= b <= 10^10000),求 a 到 b 之间(包括a和b)的数字中,有多少个数字是包含9的(例如 19,910 等都是包含9的数字)。

输入

第一行为一个数字 T (0 < T <= 100) 表示数据组数。
之后的 T 行,每行包含两个数 a 和 b (0 <= a <= b <= 10^10000)。

输出

对每组数据输入,输出一个数字,表示 a 到 b 之间的数字中(包括a和b),有多少个数字是包含9的。(注意:答案可能很大)



测试输入关于“测试输入”的帮助期待的输出关于“期待的输出”的帮助时间限制关于“时间限制”的帮助内存限制关于“内存限制”的帮助额外进程关于“{$a} 个额外进程”的帮助测试用例 1以文本方式显示

  1. 1↵
  2. 0 9↵
以文本方式显示
  1. 1↵
1秒64M0题解:

感觉这个题挺难的,题目写的很简单,但是思考量非常大。看了好几个博客问了几个人终于才弄明白。

首先要知道:从0到10^n一共有10^n-9^n个含9的数,在遇到9之前就一直这样算,遇到9之后就直接加上9之后的那些数即可。

比如13012958就是求10000000的9+3000000的9+10000的9+2000的9+900的9+58(900到957,一共是58个数)

也就是先从前往后走,在遇到9之前算(10^n-9^n)*a,遇到9之后直接加(也就还是a*10^n,就不用减9^n了)

由于数据很大,所以用很多个int数组来存,最后逐一输出,除了第一个之外其他的数组在输出的时候都要补前缀0.数据有10^10000,而int只存10^8,所以开1300个int数组就够储存的了。

还有要注意的是大数相加相减和相乘,这里要记得取模进位。

AC代码:

#include<stdio.h>  #include<string.h>  #define mod 100000000  //因为int是有精度范围的,所以加一个mod以防止爆int,最后输出的时候再逐个输出  #define last 4000  //last是假定的答案最后一位,一开始开太大了就T了 TAT  char start[10005], end[10005];  int res1[4005], res2[4005], res[4005];    void add(int a[], int ak)  {      int i;      a[last] += ak;      for (i = last; i >= 0; i--)      {          if (a[i] >= mod)          {              a[i] = a[i]-mod;              a[i - 1]++;          }//进位          else break;      }  }  void multi(int a[], int ak)  {        int i, k;      int j = 0;      while (!a[j])          j++;//找到非0的第一位      for (i = last; i >= j; i--)          a[i] = a[i]*ak;      k = 0;      for (i = last; i >= j - 2; i--)      {          a[i] += k;          k = a[i] / mod;          a[i] = a[i] % mod;      }//进位  }  void minus(int a1[], int a2[], int a3[])  {      int i;      for (i = last; i >= 0; i--)      {          a1[i] = a2[i] - a3[i];      }      for (i = last; i >0; i--)      {          if (a1[i] < 0)          {              a1[i - 1] --;              a1[i] += mod;          }      }  }//a1是结果数组    int ans1[10005] = { 0 }, ans2[10005];//分别储存乘10和9  void fun(char a[],int b)  {      memset(ans1, 0, sizeof(ans1));      memset(ans2, 0, sizeof(ans2));      int i;      int c[10005];      for (i = 0; i < strlen(a); i++)          c[i] = a[i] - '0';      ans1[last] = c[0];//给第一个元素赋初值      ans2[last] = c[0];      int flag = 0;      if (c[0] == 9)          flag = 1;      for (i = 1; i < strlen(a); i++)      {          multi(ans1, 10);          add(ans1, c[i]);//每次都把ans1乘10再把a加到ans1里          multi(ans2, 9);//把ans2乘9(即求9^n)          if (!flag)              add(ans2, c[i]);//如果前面的数里面有9,就不用再加了          if (c[i] == 9)              flag = 1;      }      if (b == 1)          minus(res1, ans1, ans2);//最后再把它们减一下      else          minus(res2, ans1, ans2);  }    int main()  {      int t;      scanf("%d", &t);      while (t--)      {          scanf("%s%s", start, end);          int len1, len2;          len1 = strlen(start);          len2 = strlen(end);          fun(start, 1);          fun(end, 2);          minus(res, res2, res1);          int i;          for (i = 0; i < len2;i++)          if (end[i] == '9')          {              res[last]++;//说明最后一个没有算上              break;          }          i = last;          while (res[i] >= mod)          {              res[i - 1]++;              res[i] -= mod;              i--;          }          i = 0;          while (!res[i]&&i<=last)              i++;//把前缀的0全都跳过去          printf("%d", res[i]);//第一个不用补0          i++;          while (i <= last)          {              printf("%08d", res[i]);//res数组中不足8位的就补0              i++;          }          printf("\n");      }      return 0;  }  


测试输入关于“测试输入”的帮助期待的输出关于“期待的输出”的帮助时间限制关于“时间限制”的帮助内存限制关于“内存限制”的帮助额外进程关于“{$a} 个额外进程”的帮助测试用例 1以文本方式显示
  1. 1↵
  2. 0 9↵
以文本方式显示
  1. 1↵
1秒64M0
0 0
原创粉丝点击