凌乱的地下室

P2100 凌乱的地下室

思路一

注:由于本题数据过大,这里只讲解思路以及 50 分代码,高精度请自便。

不妨设当有 n 个方块时,可能的摆放数为 f(n)

显然f(1)=1,f(2)=2

当计算 f(3) 时,不妨进行模拟(用1,2,3..代表方块):

f(2)[1221]f(3)[123132213]f(3)=3

不妨我们再模拟一下f(4)

f(3)=3  [123132213]f(4)[12341243132421342143]f(4)=5

由此我们可以大概猜测:数列f(n)是以1,2为前两项的斐波那契数列。

其实到这里已经可以做题了,但作为一名优秀的数学学子,这种不完全归纳法是不一定正确的,所以我们不妨浅证明一下:

可以看到,当由 n1 递推 n 时,只有最后一个数为 n1 的情况才会产生两种情况,而其他都只会有一种。

eg:n=3   [123(1)132(2)213(3)]n=4(1)(3)2(2)44n=5

而这个末尾为n的情况是如何产生的呢?

自然是在n1的每一重情况后面都加上一个n就得到了。

由此可得:

n>=2f(n)=f(n1)+f(n2)

再用数学归纳法证明即可。

CODE(50tps)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn = 3123123;
ll ll_maxn=1e18;
inline ll read_int(){
    ll a=0,f=0,g=getchar();
    while(g<'0'||g>'9'){if(g=='-') f=1;g=getchar();}
    while('0'<=g&&g<='9') a=a*10+g-'0',g=getchar();
    return f ? -a : a;
}

inline void write(ll s,bool f){
    ll top=0,a[40];
    if(s<0) s=-s,putchar('-');
    while(s) a[++top]=s%10,s/=10;
    if(top==0) a[++top]=0;
    while(top) putchar(a[top]+'0'),top--;
    if(f) putchar('\n');
}

const ll mod=1e8; 
const ll maxm = 5;
struct JZ{
    ll jz[maxm][maxm];
    ll m,n;
    inline void clear(){memset(jz,0,sizeof jz),n=0,m=0;}
    JZ operator * (JZ a) const{
        JZ b;
        b.clear();
        b.m=m,b.n=a.n;
        for(ll i=1;i<=b.m;i++){
            for(ll e=1;e<=b.n;e++){
                for(ll k=1;k<=n;k++){
                    b.jz[i][e]+=jz[i][k]*a.jz[k][e];
                    b.jz[i][e]%=mod;
                }
            }
        }
        return b;
    }
    inline void _write(){
        for(ll i=1;i<=m;i++){
            for(ll e=1;e<=n;e++){
                write(jz[i][e],0),putchar(' ');
            }
            puts("");
        }
    }
    inline void build(ll M,ll N){
        clear();
        m=M,n=N;
        for(ll i=1;i<=m;i++){
            for(ll e=1;e<=n;e++){
                jz[i][e]=read_int();
            }
        }
    }
    inline void bz(ll N){
        clear();
        n=m=N;
        for(ll i=1;i<=n;i++) jz[i][i]=1;
    }
};

inline void read(){
	JZ a1,b1;
	ll n=read_int()-1;
	a1.clear();
	a1.m=2,a1.n=1;
	a1.jz[1][1]=1,a1.jz[2][1]=2;
	b1.bz(2);
	JZ a2;
	a2.clear();
	a2.m=a2.n=2;
	a2.jz[1][1]=0,a2.jz[1][2]=1,a2.jz[2][1]=1,a2.jz[2][2]=1;
	while(n){
		if(n&1) b1=b1*a2;
		a2=a2*a2,n>>=1;
	}
	a1=b1*a1;
	write(a1.jz[1][1],1);
}

int main (){
	ll T=read_int();
	while(T--)	read();
}

思路二

既然知道了是斐波那契数列,为什么不直接用其通项公式计算呢?

CODE(100tps)

//题解 
#include<bits/stdc++.h>
using namespace std;
map<long long ,long long>mmp;     //map优化递归求斐波拉契
long long a,b,c,d;
long long dfs(long long a){
	if(a==1) return 1;
	if(a==2) return 1;
	if(mmp[a]!=0) return mmp[a];
	else return 
		mmp[a]=a%2==0?(dfs(a/2)+2*dfs(a/2-1))*dfs(a/2)%100000000 :
		 (dfs(a/2)*dfs(a/2)+dfs(a/2+1)*dfs(a/2+1))%100000000;
}        //通项公式求斐波拉契
inline long long read(){
	long long X=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) X=(X*10+ch-'0')%150000000,ch=getchar();
	return X;
}     //取摸150000000直接在快速读入中进行
int main(){
	a=read();
	cout<<dfs(a+1);
}          //主程序真短

posted @   轩Demonmaster  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示