BuringStraw

BuringStraw

【AHOI2012】ツリーハウスの階段

問題#

image

入力形式:

1つの正の整数N(1<=N<=500)、階段の高さを表します。

出力形式:

構築方法の数を表す1つの正の整数。(注:構築方法の数は非常に大きくなる可能性があります)

分析#

人肉打表で規則を見つける厳密に証明したところ、これはカタラン数であることがわかりました。

そして 500 項目まで求める必要があります #(スプレー)

したがって、これは優れた高精度のボードでもあります。

コード#

まずは高精度部分(2 つのボードの codemix)

struct bigNum{
	private:
		short t[1005];int siz;
		
		
	public:
		bigNum(string a){
			memset(t,0,sizeof(t));
			int len=a.size();
			for(int i=0;i<a.size();++i){
				t[len-i]=a[i];
			}
			siz=len;
		}
		
		bigNum(void){
			memset(t,0,sizeof(t));
			siz=0;
		}
		
		bigNum(long long x){
			memset(t,0,sizeof(t));
			int ws=0;
			while(x){
				++ws;
				int q=x%10;
				x/=10;
				t[ws]=q;
			}
			siz=ws;
		}
		
		void print(void){
			for(int i=siz;i>=1;--i){
				putchar(t[i]+'0');
			}
			putchar('\n');
		}
		
		int size(void){
			return siz;
		}
		
		friend bigNum operator *(bigNum a,long long b){
			bigNum c;
			int len=a.size()+20,g=0;
			for(int i=1;i<=len;++i){
				c.t[i]=a.t[i]*b;
			}
			for(int i=1;i<=len;++i){
				if(c.t[i]>9){
					c.t[i+1]+=c.t[i]/10;
					c.t[i]=c.t[i]%10;
				}
			}
			while(len>1&&c.t[len]==0)--len;
			c.siz=len;
			return c;
		}
		
		friend bigNum operator *(long long b,bigNum a){
			return a*b;
		}
		
		friend bigNum operator *(bigNum a,bigNum b){
			bigNum c;
			int	len=a.size()+b.size();
			for(int i=1;i<=a.size();++i){
				for(int j=1;j<=b.size();++j){
					c.t[i+j-1]+=(a.t[i]*b.t[j]);
				}
			}
			
			for(int i=1;i<=len;++i){
				if(c.t[i]>9){
					c.t[i+1]+=c.t[i]/10;
					c.t[i]=c.t[i]%10;
				}
			}
			while(len>1 && c.t[len]==0)len--;
			c.siz=len;
			return c;
		}
		
		friend bigNum operator /(bigNum a,long long b){
			bigNum c;
			int k=a.size(),g=0;
			for(int i=k;i>0;--i){
				g=g*10+a.t[i];
				c.t[i]=g/b;
				g%=b;
			}
			while(k>1&&c.t[k]==0)--k;
			c.siz=k;
			return c;
		}
		
		friend bigNum operator /(long long b,bigNum a){
			return a/b;
		}
		
		friend bigNum operator +(bigNum a,bigNum b){
			bigNum c;
			int g=0,k=max(a.size(),b.size());
			for(int i=1;i<=k;i++){
				c.t[i]=a.t[i]+b.t[i]+g;
				g=c.t[i]/10;
				c.t[i]%=10;
			}
			if(g>0){
				c.t[++k]=g;
			}
			c.siz=k;
			return c;
		}
};

次にカタラン数部分、

この問題の不思議な点は、再帰を使うと私のところでは RE が発生し、洛谷や cqyzoj では発生しないことです。。。

推論を使うとタイムアウトします。。。

訂正:あまりにも奇妙な推論を使う

再帰的な求め方(公式 2):

bigNum ktl(int x){
	if(x<=0)return 0;
	if(x==1)return 1;
	if(k[x].size())return k[x];
	else return k[x]=(4*x-2)*ktl(x-1)/(x+1);
}

“あまりにも奇妙な” 推論による求め方(公式 1):

bigNum ktl(int n){
    for(int i=2;i<=n;++i){
        for(int j=0;j<i;++j){
//			printf("%d %d\n",i,j);
            k[i]=k[i]+(k[j]*k[i-j-1]);
            //ans.print();
        }
    }
    return k[n];
}

(k の宣言):

bigNum k[510]={(bigNum)1,(bigNum)1};

以下は完全なコードです。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

struct bigNum{
	private:
		short t[1005];int siz;
		
		
	public:
		bigNum(string a){
			memset(t,0,sizeof(t));
			int len=a.size();
			for(int i=0;i<a.size();++i){
				t[len-i]=a[i];
			}
			siz=len;
		}
		
		bigNum(void){
			memset(t,0,sizeof(t));
			siz=0;
		}
		
		bigNum(long long x){
			memset(t,0,sizeof(t));
			int ws=0;
			while(x){
				++ws;
				int q=x%10;
				x/=10;
				t[ws]=q;
			}
			siz=ws;
		}
		
		void print(void){
			for(int i=siz;i>=1;--i){
				putchar(t[i]+'0');
			}
			putchar('\n');
		}
		
		int size(void){
			return siz;
		}
		
		friend bigNum operator *(bigNum a,long long b){
			bigNum c;
			int len=a.size()+20,g=0;
			for(int i=1;i<=len;++i){
				c.t[i]=a.t[i]*b;
			}
			for(int i=1;i<=len;++i){
				if(c.t[i]>9){
					c.t[i+1]+=c.t[i]/10;
					c.t[i]=c.t[i]%10;
				}
			}
			while(len>1&&c.t[len]==0)--len;
			c.siz=len;
			return c;
		}
		
		friend bigNum operator *(long long b,bigNum a){
			return a*b;
		}
		
		friend bigNum operator *(bigNum a,bigNum b){
			bigNum c;
			int	len=a.size()+b.size();
			for(int i=1;i<=a.size();++i){
				for(int j=1;j<=b.size();++j){
					c.t[i+j-1]+=(a.t[i]*b.t[j]);
				}
			}
			
			for(int i=1;i<=len;++i){
				if(c.t[i]>9){
					c.t[i+1]+=c.t[i]/10;
					c.t[i]=c.t[i]%10;
				}
			}
			while(len>1 && c.t[len]==0)len--;
			c.siz=len;
			return c;
		}
		
		friend bigNum operator /(bigNum a,long long b){
			bigNum c;
			int k=a.size(),g=0;
			for(int i=k;i>0;--i){
				g=g*10+a.t[i];
				c.t[i]=g/b;
				g%=b;
			}
			while(k>1&&c.t[k]==0)--k;
			c.siz=k;
			return c;
		}
		
		friend bigNum operator /(long long b,bigNum a){
			return a/b;
		}
		
		friend bigNum operator +(bigNum a,bigNum b){
			bigNum c;
			int g=0,k=max(a.size(),b.size());
			for(int i=1;i<=k;i++){
				c.t[i]=a.t[i]+b.t[i]+g;
				g=c.t[i]/10;
				c.t[i]%=10;
			}
			if(g>0){
				c.t[++k]=g;
			}
			c.siz=k;
			return c;
		}
};

bigNum k[510]={(bigNum)1,(bigNum)1};

/*bigNum ktl(int x){
	if(x<=0)return 0;
	if(x==1)return 1;
	if(k[x].size())return k[x];
	else return k[x]=(4*x-2)*ktl(x-1)/(x+1);
}*/

bigNum ktl(int n){
	for(int i=2;i<=n;++i){
		k[i]=(4*i-2)*k[i-1]/(i+1);
	}
	return k[n];
}

int main(void){
	int n;
	cin>>n;
	ktl(n).print();
//	bigNum a(123),b(45);
//	(a*b).print();
	return 0;
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。