九连环
题解
一看到这题目,就知道不是什么好题。
好吧,一眼就感觉是个dp。根据样例解释我们很容易发现:
令为i连环所需的最小步数,则
。
哇,这么简单。忽然发现数据范围为1e5,要炸!!!
高精明显会TLE,所以我们来想一想如何用其它方法做。
巨佬可忽略下面这段。
我们把每个的值列出来:
1,2,5,10,21,...
完全没有规律,咋办?不你看错了,有规律的,换成2进制。
1,10,101,1010,10101,...
发现了规律,1与0间断出现。接下来我们把相邻两个相加:
1,11,111,1111,11111,...
所以,因此
,然后,就可以用FFT快速幂快速算出了。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#define MAXN 150000
using namespace std;
typedef long long LL;
//#define int LL
const int W=10;
const double PI=acos(-1);
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
int rev[MAXN];
struct complex{
double x,y;
complex(){x=y=0;}
complex(double _x,double _y):x(_x),y(_y){}
complex operator + (complex b){return complex(x+b.x,y+b.y);}
complex operator - (complex b){return complex(x-b.x,y-b.y);}
complex operator * (complex b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);}
};
void FFT(int lim,complex *a,int typ){
for(int i=0;i<lim;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
for(int i=1;i<lim;i<<=1){
complex T(cos(PI/i),typ*sin(PI/i));
for(int W=i<<1,j=0;j<lim;j+=W){
complex n(1,0);
for(int k=0;k<i;++k,n=n*T){
complex x(a[j+k]),y(n*a[i+j+k]);
a[j+k]=x+y;a[i+j+k]=x-y;
}
}
}
}
struct bignum{
int num[MAXN],len;
bignum(){
memset(num,0,sizeof(num));len=1;
}
bignum(int x){
memset(num,0,sizeof(num));len=0;
if(!x){len=1;return;}
while(x)num[len++]=x%W,x/=W;
}
void print(){
for(int i=len-1;i>=0;i--)
printf("%d",num[i]);
puts("");
}
void operator /= (int x){
int ys=0,lenn=0;
for(int i=len-1;i>=0;i--){
ys=ys*W+num[i];
if(ys<x)num[i]=0;
else{
if(!lenn)lenn=i+1;
num[i]=ys/x;ys%=x;
}
}
len=max(lenn,1);
}
void operator *= (const bignum b){
static complex A[MAXN],B[MAXN];
int lenn=len+b.len-1,lim=1,L=0;while(lim<lenn)lim<<=1,L++;
rev[0]=0;for(int i=1;i<=lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<L-1);
for(int i=0;i<lim;i++){
A[i]=complex(i<len?num[i]:0,0);
B[i]=complex(i<b.len?b.num[i]:0,0);
}
FFT(lim,A,1);FFT(lim,B,1);
for(int i=0;i<lim;i++)A[i]=A[i]*B[i];FFT(lim,A,-1);
for(int i=0;i<lenn;i++)num[i]=(int)(A[i].x/lim+0.5);
len=lenn;num[len]=0;
for(int i=0;i<len;i++)num[i+1]+=num[i]/W,num[i]%=W;
if(num[len])len++;
}
}res,a;
int m,n;
signed main(){
read(m);
while(m--){
read(n);n++;
res=bignum(1),a=bignum(2);
while(n){
if(n&1)res*=a;
a*=a;n>>=1;
}
res/=3;
res.print();
}
return 0;
}