bzoj 1265 //1265: [AHOI2006]斐波卡契的兔子(kacci)

bzoj 1265 //1265: [AHOI2006]斐波卡契的兔子(kacci)   //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1265

更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录

第1阶段

//1265: [AHOI2006]斐波卡契的兔子(kacci)
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1265
//1 < = k < = 10^ 6 000高精度无疑了
//兔子当月不会生产,3个月后,新兔子变成旧兔子,新兔子有3个月适应期。
//此文http://blog.sina.com.cn/s/blog_5d721d420102v7mf.html思路不错,摘抄如下
/*
 首先明确,得用高精度。

记F[i][0]为第i个月时已出生0个月(即第i月出生的)的兔子数;F[i][1]为第i个月时已出生1个月的兔子数;F[i][2]为第i个月时已出生2个月的兔子数;F[i][3]为第i个月时已出生3个月及以上的兔子数。

易得方程:
F[i][0]=a*F[i-1][0]+b*F[i-1][1]+c*(F[i-1][2]+F[i-1][3])
F[i][1]=F[i-1][0]
F[i][2]=F[i-1][1]
F[i][3]=F[i-1][2]+F[i-1][3]
其中边界条件:F[0][0]=1 F[0][1]=F[0][2]=F[0][3]=0
那么我们就可以得到第一个答案P=F[m][0]+F[m][1]+F[m][2]+F[m][3]

然后我们要求K/P(向上取整),高精度除法我们可以用倍增法:
记power2[i]表示2^i
找到最大的x满足power2[x]*P<=K(其实power2[x]*P不一定要用高精度乘法,如power2[0]*P=P,power2[1]*P=P+P,power2[2]*P=P+P+P+P=(P+P)+(P+P)……用高精度加法法就可以了)
从大到小枚举x,如果K-power2[i]*P>=0,那么ans+=power2[i],K-=power2[i]*P。
因为要向上取整,我们最后要判断一下。
*/
//首先编个非高精度算法
//以下代码为非高精度算法,能通过样例,虽然无法让读者AC,但能让读者迅速明白解题思路。2019-10-24
#include
#define maxn 3010
#define LL long long
LL a,b,c,m;
LL f[maxn][4];
int main(){
    int i;
    LL p,k,q;
    scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&m,&k);
    f[0][0]=1,f[0][1]=f[0][2]=f[0][3]=0;//初始化
    for(i=1;i<=m;i++){
        f[i][0]=f[i-1][0]*a+f[i-1][1]*b+f[i-1][2]*c+f[i-1][3]*c;//在i月,刚出生的兔子数量
        f[i][1]=f[i-1][0];//在i月,已出生1月的兔子数量
        f[i][2]=f[i-1][1];//在i月,已出生2月的兔子数量
        f[i][3]=f[i-1][2]+f[i-1][3];//在i月,已出生3月及3月以上的兔子数量
    }
    p=f[m][0]+f[m][1]+f[m][2]+f[m][3];
    printf("%lld\n",p);
    if(k%p)q=k/p+1;
    else q=k/p;
    printf("%lld\n",q);
    return 0;
}

第2阶段

//将代码改造成非数组形式,方便接下来高精度算法编写。2019-10-26 9:07
//样例通过,非高精度算法。
#include
#define LL long long
LL A,B,C,M;
LL a,b,c,d,ta,tb,tc,td;
int main(){
    int i;
    LL p,K,q;
    scanf("%lld%lld%lld%lld%lld",&A,&B,&C,&M,&K);
    a=1,b=c=d=0;//初始化
    for(i=1;i<=M;i++){
        ta=a,tb=b,tc=c,td=d;
        a=ta*A+tb*B+tc*C+td*C;//在i月,刚出生的兔子数量
        b=ta;//在i月,已出生1月的兔子数量
        c=tb;//在i月,已出生2月的兔子数量
        d=tc+td;//在i月,已出生3月及3月以上的兔子数量
    }
    p=a+b+c+d;
    printf("%lld\n",p);
    if(K%p)q=K/p+1;
    else q=K/p;
    printf("%lld\n",q);
    return 0;
}

第3阶段

157240 kb 624 ms C++/Edit 3480 B

//此文https://blog.csdn.net/cdqzoiers/article/details/52531231代码写得不错。
/*
我们用x,y,z表示一个月、两个月、三个月及以上的兔子,那么每次x=ax+by+cz,y=x,z=y+z就可以求出p,而q就是k/p向上取整
k/p可以用p,2p,4p,…,(2^t)p去求
然而为什么AC的人这么少呢。。

难点在于除法

用样例来解释:k/p
10000/89
2^0*89=89
2^1*89=178
2^2*89=356
2^3*89=712
2^4*89=1424
2^5*89=2848
2^6*89=5696

ans=0
10000-5696=4304, ans+=2^6, ans=64
4304-2848=1456, ans+=2^5, ans=96
1456-1424=32, ans+=2^4, ans=112
0<32<89,   结果需+1,  ans+=1,ans=113
*/

程序AC后,感慨万千,该题网上资料少,需要及时总结,以期对后人有用。2019-10-26 16:36

该题难点如下:
1.高精度减法,要特别注意,结果为0时的位数特判,注意是x[0]=1,x[1]=0;而不是x[0]=0,x[1]=0
2.该题最多只能用7位位压,8位位压要溢出。
3.高精度加法,套用函数时,要特别注意数据1的初始化。
4.在高精度除的运算中,注意数组空间的大小,是可以运算出来的,结果很大。
5.该题要小心超出题中内存限制。时时注意计算所用内存。

//每编写一个函数,要马上测试,不然,高精度算法,查起代码,头都大。2019-10-26 9:40
//样例通过,提交Wrong_Answer.失望。2019-10-26 10:50
//注意f[20010][maxn/BIT],g[20010][maxn/BIT]需要开到20010
//提供一组样例
/*
输入
0 0 0 1
10
输出
1
10
因此修改了一处错误
if(i==0)i=1;//此句最难,对x[1]=0,x[0]=1;进行特判,漏了此句,造成错误。
*/
//再提供一组样例
/*
输入
100 100 100 3000
1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
输出
9207067941189489846389136081204931047487231552431168292234798953729627193114026486263110218236024810959902324879065601273939355953838487689940084149633790579084876631402281851128554366507920148246224811656936041853479484173588170895939908282752645976830404447786204729018902989647067489504447911570563803807519121222616683117705909468275312633581729644580624057163326646093017110109633082666317089309577793994119866038124539502919574393783342330102789763001517723454116494475680653052928411391115335264268274989291508324787223065068186887804535416670886273423776254946686139414888744971815647048785137304925251566376790627441666031232525350537048871943774326620868894711889993048663505119854828397270623632847604724101544002373335801065694278768017202912046113290844005760976241018370931732292205307857113847548892224927433587109845653614912366149396884292809360999120696344019372282669248297896426561577314301771621003471981310675673062897709732094103209231103735722788716764001946488563116404537428806777978241019677100134958998651371696328281867296325008432443140379033833482135286911070975186956750054500639682856144554544341151092127963821583676610862960850788371238826927131094896960438028858382745440629772719066249117293940119878227223156153501386119856833086758050295989312898738972452854913487815565062763659674248768832443961922346403937682882809187301229474417735129229600301648185174613047650325779261128762411755136282010368899044853314447335441051723274342127575038405308240175433242844489544825691982448133882428974784104958348419744555360176240368035613690941336018375078207559524670327427078011501003869370972256475185771145062137035404322488386738328966273031531495406241957643076135306902809196455797923081903367164596432413616180357200661552015462245084236744839196626468749819314968363877828158016581249387710779086646159505967781082945668163788439467479635725391920139299783293027172049731757414806853387528377014808237410959446601641744510873435529134551575017320825947720402229007593429140981703503020494584240452428018796204892427938849937214549307871276492444150406756112383789632756950292038267919906370215196456247969259741723587632051213182129596347249907717180611983615264535712298142512562680687030189804055719778735095896163675490182471881532842094268500421730098038271357081330746404375150552389591746530458972649389745652173247774164390833290133282493613473336979895496713509756646847758391496660355641834010345287565479786824500296186868632384916058848705529186090458765553001316845220947751465075573654429078237507086791117219596968670476317555937981107388927811507390773894576627141595182496620416712833305650327800412170479329750782641755464138618211305492546405898301867669714603513509218621340881865645090560088517138754531430477958384482324601370868703219885576477079528415342537312982048017248661612652373790386538166551158192466092381220152334323081244541316073367004324103141931737880747814693290805778303282092424996984377462137832820492965662002849938985728004073950311222830554924386989453220488848083171157749436385441205739260968839571702267505771131251285934956768823829714101015178130329731287622722466455429633019986435895062170220982596114341349742177831172438966541185808616144756994972284858147273255235993439230909414799901319499443975992640516003084608507726670715788266497639868172162817184338284931093660377443341821109295629313838280840414556166587376472882924702327179336551472492915888056819791061384118912227525048006454294613388763142110514908456368046569418465576954629875323860909608667432055528940438490564463729621910220489480143575676450747797796466005048865157380060567088274846028448179994390309146873017474379535156655800621482198288298421403998095640408525879354211742089959222049416434746525170051180465496557222157971799035750661461551322706815526317075398115505659941451804314147684627190467526582238958856881837775589296071955312232156346313846866233687857017395450870148757037358245778771952464168154236587949734491529474322725520051853733811075632915969193089815037313821257873463639007991571120906736448566409532054982986867806843233485913025692273622574263287768544594849787230495596566523230157580062047625012735798300215483529257377359178822312258295293970169217820086367961529613961996682740357032434267864005458950638584512741872401021104750651510463997801844893364812286167009040396165000678804633701099603118884704001382569413846662148797313777625298489993019128815160194041670771183452160395661794702907059013260335402625958113643492283267542748581772953672211443856882226076530824652391163976802047261190925363904351621813317091557321824933651667289401840326805485986444045338888423710865637132576485804823807064703327314412048125801065704638553823623158742757695593636346343419088391756059689774302177839269366130447979927288670359655168143374834104546737445608645895859693314544133623096115897142542780467436183956517932402213084721483352232457241720595950960290440934750333557971264361704400104963110436393323967711401025322651920138410555881077207594271969590973198233451083942161489898335032839180776826692689186007537616810709279817682279858731386805511301821403182809536071812076049723770153650123849201069347372448683070628115120460803192091242655622541748169321829490994930941168263792593704453593388612400232987043345974219753925218487394693246891397485765290145963676275698954701123823875416160593158140882001496133376770150916175792323686733977861058695585693351168930120709038288215713983736705547591116282773892581710863269047048745839291561925953469221655532445325109394769978426985188496928409724297708543187231499138294710772169969688749826843566760043318698362008841526397319972789475495203234590820540411747019880693586002394518575555647591229486361521727874344645278543356486614273934905053360329906357716181519428384415281725861929671614944586960237649534630265584489630399368615466355817880033891821449374784412092588127635314264888987427498008133588640223793723281785215278088099618116913970985300001
1
*/
//2^31-1=2147483647   99999999*100=9999999900  9999999900>2147483647 要溢出8位压位不行,至多只能7位压位
//上述样例通过,提交Memory_Limit_Exceed    179304 kb    0 ms    C++/Edit    3313 B    
//发现#define maxn 7000//此处错写成#define maxn 8000
//修改,提交Wrong_Answer    157240 kb    4 ms    C++/Edit    3347 B
//仔细对照上述样例输出结果,发现未完全对上
//排查,发现for(i=x[0]-1;i>=1;i--)printf("%07d",x[i]);//此处错写成for(i=x[0]-1;i>=1;i--)printf("%08d",x[i]);
//修改,上述样例通过,提交Wrong_Answer    157240 kb    16 ms    C++/Edit    3408 B
//对照上述样例,基本确认,问题应该出在  输出的第2个数据上  2019-10-26 15:51
//再提供一组样例
/*
输入
1 2 3 20
10000000000000000
输出
103363394
96746050
*/
//排查,发现memset(r0,0,sizeof(r0)),r0[0]=1,r0[1]=1;//此处错写成r0[0]=1,r0[1]=1;
//上述样例通过,提交Accepted    157240 kb    608 ms    C++/Edit    3465 B  2019-10-26 16:15 排查花了100分钟
//上述过程,主要借助对拍,即与AC代码对比输出数据。
//解释f[20010][maxn/BIT]中的20010如下
//因a=b=c=100,m=3000,k=10^6000 即最后兔子数是10^6000;2^x=10^6000   x=log(10^6000)/log2=19931.568569324
#include
#include
#define maxn 7000//此处错写成#define maxn 8000
#define BASE 10000000//此处错写成#define BASE 100000000
#define BIT 7//此处错写成#define BIT 8
int A,B,C,M,K[maxn];
int a[maxn/BIT],b[maxn/BIT],c[maxn/BIT],d[maxn/BIT],ta[maxn/BIT],tb[maxn/BIT],tc[maxn/BIT],td[maxn/BIT];
int r0[maxn/BIT],r1[maxn/BIT],r2[maxn/BIT],r3[maxn/BIT],P[maxn/BIT];
int f[20010][maxn/BIT],g[20010][maxn/BIT],ans[maxn/BIT];//此处错写成int f[1000][maxn],g[1000][maxn],ans[maxn/BIT];
char s[maxn];
void read(int *x){
    int len,i,tmp;
    char t;
    scanf("%s",s+1);
    len=strlen(s+1);
    for(i=1;i<=len/2;i++)
        t=s[i],s[i]=s[len-i+1],s[len-i+1]=t;
    x[0]=(len-1)/BIT+1;
    for(i=1;i<=len;i++){//此处错写成for(i=1;i<=x[0];i++){
        if((i-1)%BIT==0)x[(i-1)/BIT+1]=0,tmp=1;
        x[(i-1)/BIT+1]+=(s[i]-'0')*tmp;
        tmp*=10;
    }
}
void print(int *x){
    int i;
    printf("%d",x[x[0]]);
    for(i=x[0]-1;i>=1;i--)printf("%07d",x[i]);//此处错写成for(i=x[0]-1;i>=1;i--)printf("%08d",x[i]);
    printf("\n");
}
void multo(int *x,int *y,int v){//x=y*v
    int i;
    x[1]=0;
    for(i=1;i<=y[0];i++){
        x[i]+=y[i]*v;
        x[i+1]=x[i]/BASE;
        x[i]%=BASE;
    }
    while(x[i])i++;//考虑数据可能会变长
    x[0]=i-1;
}
void add(int *x,int *y){//x+=y
    int i;
    x[0]=x[0]>y[0]?x[0]:y[0];
    for(i=1;i<=x[0];i++){
        x[i]+=y[i];
        x[i+1]+=x[i]/BASE;
        x[i]%=BASE;
    }
    while(x[i])i++;//考虑数据可能会变长
    x[0]=i-1;
}
int cmp(int *x,int *y){//x>y 1;x==y 0;x     int i;
    if(x[0]>y[0])return 1;
    if(x[0]     for(i=x[0];i>=1;i--){//x[0]==y[0]
        if(x[i]>y[i])return 1;
        if(x[i]     }
    return 0;
}
void dec(int *x,int *y){//x-=y
    int i;
    for(i=1;i<=x[0];i++){
        x[i]-=y[i];
        if(x[i]<0)x[i+1]-=1,x[i]+=BASE;
    }
    while(!x[i])i--;//数据长度可能变短
    if(i==0)i=1;//此句最难,对x[1]=0,x[0]=1;进行特判,漏了此句,造成错误。
    x[0]=i;
}
void solve(){
    int i,MX;
    a[0]=1,a[1]=1,b[0]=c[0]=d[0]=1,b[1]=c[1]=d[1]=0;//此处错写成a[0]=0,a[1]=1,b[0]=c[0]=d[0]=1,b[1]=c[1]=d[1]=0;
    for(i=1;i<=M;i++){
        memcpy(ta,a,sizeof(a)),memcpy(tb,b,sizeof(b));
        memcpy(tc,c,sizeof(c)),memcpy(td,d,sizeof(d));
        multo(r0,ta,A),multo(r1,tb,B),multo(r2,tc,C),multo(r3,td,C);
        memset(a,0,sizeof(a)),a[0]=1,a[1]=0,add(a,r0),add(a,r1),add(a,r2),add(a,r3);//此处错写成add(a,r0),add(a,r1),add(a,r2),add(a,r3);
        memcpy(b,ta,sizeof(ta));
        memcpy(c,tb,sizeof(tb));
        memset(d,0,sizeof(d)),d[0]=1,d[1]=0,add(d,tc),add(d,td);//此处错写成add(d,tc),add(d,td);
    }
    P[0]=1,P[1]=0;
    add(P,a),add(P,b),add(P,c),add(P,d);
    print(P);
    memcpy(f[0],P,sizeof(P)),g[0][0]=1,g[0][1]=1;
    for(i=0;cmp(K,f[i])>=0;i++){//此处错写成for(i=0;cmp(P,f[i])>=0;i++){
        multo(f[i+1],f[i],2);
        multo(g[i+1],g[i],2);
    }
    MX=i-1,ans[0]=1,ans[1]=0;
    for(i=MX;i>=0;i--)
        if(cmp(K,f[i])>=0){//此处错写成if(cmp(P,f[i])>=0){
            dec(K,f[i]);//此处错写成dec(P,f[i]);
            add(ans,g[i]);
        }
    memset(r0,0,sizeof(r0)),r0[0]=1,r0[1]=1;//此处错写成r0[0]=1,r0[1]=1;
    if(!(K[0]==1&&K[1]==0))add(ans,r0);//此处错写成if(!(P[0]==1&&P[1]==0))add(ans,r0);
    print(ans);
}
int main(){
    scanf("%d%d%d%d",&A,&B,&C,&M);
    read(K);
    solve();
    return 0;
}

你可能感兴趣的:(跟着大佬学算法)