衆所周知,琪露諾(チルノ,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的。(注意:答案可能很大)
測試輸入 | 期待的輸出 | 時間限制 | 內存限制 | 額外進程 | |
---|---|---|---|---|---|
測試用例 1 |
以文本方式顯示
|
以文本方式顯示
|
1秒 | 64M | 0 |
感覺這個題挺難的,題目寫的很簡單,但是思考量非常大。看了好幾個博客問了幾個人終於才弄明白。
首先要知道:從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;
}