1. 程式人生 > >【NOI2015模擬8.14】A+B

【NOI2015模擬8.14】A+B

std out 一個 blog sam 數據 -a spl stream

Description

對於每個數字x,我們總可以把它表示成一些斐波拉切數字之和,比如8 = 5 + 3, 而22 = 21 + 1,因此我們可以寫成 x = a1 * Fib1 + a2 * Fib2 + a3 * Fib3 + … + an * Fibn, 其中,Fib1 = 1, Fib2 = 2…. Fib[i] = Fib[i – 1] + Fib[I - 2], 且a[n] > 0.那麽我們稱ai為x的一種斐波拉切表示,由於表示方法有很多種,我們要求最大化a[1…n],即,如果b[1…n]和a[1…m]都可以表示x,若m > n 則a更大,若 m = n, 則從高位到低位比,第一個不同處i,若ai > bi 則a比b大。

你的任務很簡單,給你兩個用斐波拉切數最大化表示的兩個數字,輸出他們相加後用斐波那契最大化表示的數字。

Input

兩行,分別表示兩個數字

每一行開頭一個n,表示長度

然後緊接著n個數字,為從低位到高位。

Output

同輸入格式。一行。

Sample Input

4 0 1 0 1
5 0 1 0 0 1

Sample Output

6 1 0 1 0 0 1

Data Constraint

對於30%的數據 長度 <= 1000

對於100%的數據 長度 <= 1000000

算出十進制值相加後再用斐波那契最大化表示顯然接受不了,我們得在序列裏找出規律。

這裏有兩個不難發現的運算法則:

1.如果有連續兩位i,i-1是1,那麽它們可以“運算”使得第三位i+1是1. 如 0 1 0 1 1 0 = 0 1 0 0 0 1

2.如果這個位i是2,那麽它可以使它的後一位i+1和前兩位i-2是1. 如 0 0 2 0 0 1 0=1 0 0 1 0 1 0

隨便弄上十幾次這樣就可以了。

技術分享
 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int f[10000002],n,x,len1,len2;
 5 int main(){
6 f[0]=0; 7 f[1]=0; 8 f[2]=0; 9 scanf("%d",&len1); 10 for (int i=1;i<=len1;i++) 11 scanf("%d",&f[i]); 12 scanf("%d",&len2); 13 for (int i=1;i<=len2;i++){ 14 int x=0; 15 scanf("%d",&x); 16 f[i]+=x; 17 } 18 int qwq=max(len1,len2); 19 int qoq=true; 20 do{ 21 qoq=false; 22 int qaq=qwq; 23 for (int i=2;i<=qwq;i++){ 24 if ((f[i-1])&&(f[i])){ 25 f[i+1]++; 26 qwq=max(qwq,i+1); 27 f[i]--; 28 f[i-1]--; 29 } 30 } 31 if (f[1]==2){ 32 f[2]++; 33 f[1]=0; 34 } 35 if (f[2]==2){ 36 f[3]++; 37 qwq=max(qwq,3); 38 f[1]++; 39 f[2]=0; 40 } 41 bool quq=true; 42 do{ 43 quq=false; 44 for (int i=3;i<=qaq;i++){ 45 if (f[i]>=2){ 46 quq=true; 47 f[i+1]++; 48 qwq=max(i+1,qwq); 49 f[i-2]++; 50 f[i]--; 51 f[i]--; 52 } 53 } 54 if (quq) qoq=true; 55 } while(quq); 56 } while(qoq); //直到沒修改為止 57 printf("%d ",qwq); 58 for(int i=1;i<=qwq;i++) 59 printf("%d ",f[i]); 60 return 0; 61 }
神奇的代碼

【NOI2015模擬8.14】A+B