題解 | A*BBBB
A*BBBB
https://ac.nowcoder.com/acm/contest/87255/D
A*BBBB:原題鏈接
題意:
給你兩個(gè)值a和b,b的每一位都相同,求它們相乘后的結(jié)果。
注意:a和b的長(zhǎng)度有1e6。
做題思路:
很顯然本題需要用到高精度,但普通高精度并不能解決本題,所以要針對(duì)本題做出優(yōu)化。
首先根據(jù)題意我們可以知道b的每一個(gè)值都是相同的,我們用個(gè)樣例,看看可以得出什么。
樣例假設(shè):a=1234,b=111
我們列出計(jì)算公式后,可以發(fā)現(xiàn)每一行的值都是相同的,在計(jì)算相加時(shí),當(dāng)前位置的值是該點(diǎn)原先的值加上它右側(cè)的值,如,個(gè)位上為4,十位上為3+4=7,百位上為2+7=9,出于累加狀態(tài)。
1 2 3 4
1 2 3 4
1 2 3 4
1 3 6 9 7 4
很顯然位置上的值不會(huì)一直出于累加狀態(tài),如千位上的值為1+2+3,將個(gè)位上的值4去除了,每個(gè)點(diǎn)上的值是怎么累加的呢,我們建個(gè)表直觀感受一下。
累加和 | 狀態(tài) |
---|---|
4 | 4 |
4,3 | 7 |
4,3,2 | 9 |
3,2,1 | 6 |
有沒有感覺到什么,是不是很像滑動(dòng)窗口,當(dāng)超出k時(shí),就將超出k的部分彈出,而這個(gè)k值很明顯就是b的長(zhǎng)度,由此可以得到一條規(guī)則
//now為計(jì)數(shù),當(dāng)在超出b的長(zhǎng)度后,此時(shí)i-lenb上的值已經(jīng)超出,所以減去
if (i>=lenb)now-=a[i-lenb]-'0';
但這顯然完成不了代碼,我們繼續(xù)模擬。
累加和 | 狀態(tài) |
---|---|
3,2,1 | 6 |
2,1 | 3 |
1 | 1 |
此時(shí)我們發(fā)現(xiàn)值一直在減少,原因很簡(jiǎn)單,它沒東西可以加了嘛,當(dāng)?shù)谝恍械闹导油陼r(shí),now也同樣不會(huì)繼續(xù)累加。
| 1 2 3 4
1 | 2 3 4
1 2 | 3 4
1 3 | 6 9 7 4
所以得出以下代碼
//當(dāng)在超出a的長(zhǎng)度前,下一位值會(huì)處于累加狀態(tài)
if (i<lena)now+=a[i]-'0';
接下來接可以使用經(jīng)典的高精度解決問題了,可能有人問這只是當(dāng)b相同值等于1的情況,要是不想同怎么辦,那么ad+bd+cd是不是等于(a+b+c)*d,所以只要在高精度計(jì)算余數(shù)的部分乘以b[0]就可以了,并不會(huì)對(duì)題目造成影響。以下是AC代碼。
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int t;
string a,b;
int main(){
cin >>t;
while(t--)
{
cin >>a>>b;
//怎么來的讓他怎么回去吧
//數(shù)組存不下本題答案
string s="";
//res記錄每次按位計(jì)算時(shí)的值
int res=0;
//因?yàn)閎每一位都相同,所以直接拿出用來計(jì)算
int op=b[0]-'0';
//拿出a,b的長(zhǎng)度,便于計(jì)算
int lena=a.size();
int lenb=b.size();
//now為當(dāng)前個(gè)位的值
int now=0;
//因?yàn)槭浅朔ㄓ?jì)算,所以最終答案的長(zhǎng)度會(huì)是兩者相加減一
int maxn=lena+lenb;
//因?yàn)閺膫€(gè)位開始算起,所以將字符串倒敘
reverse(begin(a),end(a));
for (int i=0;i<maxn;i++)
{
//當(dāng)在超出a的長(zhǎng)度前,下一位值會(huì)處于累加狀態(tài)
if (i<lena)now+=a[i]-'0';
//當(dāng)在超出b的長(zhǎng)度后,此時(shí)i-lenb上的值已經(jīng)超出,所以減去
if (i>=lenb)now-=a[i-lenb]-'0';
//計(jì)算該位置上的值
res+=now*op;
//將他的余數(shù)放入s尾
s.push_back(res%10+'0');
//并將余數(shù)除10,確保余數(shù)是個(gè)位數(shù)
res/=10;
}
//刪除前導(dǎo)0
while(s.size()>1 && s.back()=='0')s.pop_back();
//將s從逆序變正序
reverse(begin(s),end(s));
cout <<s<<"\n";
}
return 0;
}