生活随笔
收集整理的這篇文章主要介紹了
[CQOI2018]九连环
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、題目
點此看題
二、解法
根據題目中444連環的解釋,你可以發現拆除444連環滿足如下規律:
- 拆掉一個222連環,使得原環變成110011001100
- 拿掉最左邊的111
- 加二連環使其變為011101110111
- 拆三連環
這就完成了一個問題的轉化,由于拆和加環效果相同,我們定義dpidp_idpi?為拆掉iii連環需要的步數,則有遞推式:
dp[i]=2?dp[i?2]+dp[i?1]+1dp[i]=2\cdot dp[i-2]+dp[i-1]+1dp[i]=2?dp[i?2]+dp[i?1]+1可以把答案寫成二進制的形式:1 10 101 1010 10101 ..................
可以發現相鄰兩個二進制數的和是1111..1111..1111..的形式,所以 dp[i]+dp[i+1]=2i+1dp[i]+dp[i+1]=2^{i+1}dp[i]+dp[i+1]=2i+1,結合dp[n]=2dp[n?1]+(n&1)?1:0dp[n]=2dp[n?1]+(n\&1)?1:0dp[n]=2dp[n?1]+(n&1)?1:0(打表規律),可以發現答案是2i+13\frac{2^{i+1}}{3}32i+1?
這樣問題就轉化成了高精度,可以用FFT\text{FFT}FFT優化,下面寫出一些注意事項:
- 清零最重要,每個地方每個數組及時清零
- 不要把數組開在函數里面,開在函數外面反復利用
#include <cstdio>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std
;
const int MAXN
= 100005;
const double pi
= acos(-1.0);
int read()
{int num
=0,flag
=1;char c
;while((c
=getchar())<'0'||c
>'9')if(c
=='-')flag
=-1;while(c
>='0'&&c
<='9')num
=(num
<<3)+(num
<<1)+(c
^48),c
=getchar();return num
*flag
;
}
int n
,T
;
struct complex
{double x
,y
;complex() {x
=y
=0;}complex(double X
,double Y
) : x(X
) , y(Y
) {}complex
operator + (const complex
&R
) const {return complex(x
+R
.x
,y
+R
.y
);}complex
operator - (const complex
&R
) const {return complex(x
-R
.x
,y
-R
.y
);}complex
operator * (const complex
&R
) const {return complex(x
*R
.x
-y
*R
.y
,x
*R
.y
+y
*R
.x
);}
}A
[MAXN
],B
[MAXN
];
void FFT(int len
,complex
*a
,int flg
)
{if(len
==1) return ;complex a1
[len
>>1],a2
[len
>>1];for(int i
=0;i
<len
;i
+=2) a1
[i
>>1]=a
[i
],a2
[i
>>1]=a
[i
+1];FFT(len
>>1,a1
,flg
);FFT(len
>>1,a2
,flg
);const complex w
=complex(cos(pi
*2.0/len
),sin(pi
*2.0/len
)*flg
);complex k
=complex(1,0);len
>>=1;for(int i
=0;i
<len
;i
++,k
=k
*w
){a
[i
]=a1
[i
]+k
*a2
[i
];a
[i
+len
]=a1
[i
]-k
*a2
[i
];}
}
struct bignum
{int n
,a
[MAXN
];bignum() {memset(a
,0,sizeof a
);n
=1;}bignum(int x
){memset(a
,0,sizeof a
);n
=0;if(!x
) {n
=1;return ;}while(x
) a
[n
++]=x
%10,x
/=10;}void print(){for(int i
=n
-1;i
>=0;i
--)printf("%d",a
[i
]);puts("");}void operator /= (int x
){int t
=0,len
=0;for(int i
=n
-1;i
>=0;i
--){t
=t
*10+a
[i
];a
[i
]=t
/x
;t
%=x
;if(!len
&& a
[i
]) len
=i
+1;}n
=max(len
,1);}void operator *= (bignum b
){int len
=1;while(len
<=n
+b
.n
) len
<<=1;for(int i
=0;i
<len
;i
++) A
[i
]=B
[i
]=complex(0,0);for(int i
=0;i
<n
;i
++) A
[i
]=complex(a
[i
],0);for(int i
=0;i
<b
.n
;i
++) B
[i
]=complex(b
.a
[i
],0);FFT(len
,A
,1);FFT(len
,B
,1);for(int i
=0;i
<len
;i
++) A
[i
]=A
[i
]*B
[i
];FFT(len
,A
,-1);for(int i
=0;i
<n
+b
.n
;i
++)a
[i
]=0;for(int i
=0;i
<n
+b
.n
;i
++){a
[i
]+=(int)(A
[i
].x
/len
+0.5);if(a
[i
]>=10)a
[i
+1]+=a
[i
]/10,a
[i
]%=10;}for(int i
=n
+b
.n
-1;i
>=0;i
--)if(a
[i
]){n
=i
+1;break;}}
}a
,r
;
int main()
{T
=read();while(T
--){n
=read()+1;a
=bignum(2),r
=bignum(1);while(n
>0){if(n
&1) r
*=a
;a
*=a
;n
>>=1;}r
/=3;r
.print();}
}
總結
以上是生活随笔為你收集整理的[CQOI2018]九连环的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。