OpenJudge NOI 2.2 9273:PKU2506Tiling | 2.3 9273:PKU2506Tiling

【题目链接】

OpenJudge NOI 2.2 9273:PKU2506Tiling
OpenJudge NOI 2.3 9273:PKU2506Tiling

【题目考点】

1. 递推

2. 高精度

【解题思路】

解法1:递推

  • 递推状态: a i a_i ai:i列道路铺砖的方案数
  • 初始状态:0列道路铺砖有1种方案,就是不铺。1列道路铺砖只有1种方案: a 0 = 1 , a 1 = 1 a_0=1, a_1=1 a0=1,a1=1
  • 递推关系:
    • 如果第i列道路只铺一个宽为1高为2的竖向的砖,那么i列道路的铺砖方案数等于前i-1列道路的铺砖方案数 a i − 1 a_{i-1} ai1
    • 如果第i列和第i-1列道路铺了两个宽为2高为1的横向的砖,那么i列道路的铺砖方案数等于前i-2列道路的铺砖方案数 a i − 2 a_{i-2} ai2
    • 如果第i列和第i-1列道路铺了一个宽为2高为2的横向的砖,那么i列道路的铺砖方案数等于前i-2列道路的铺砖方案数 a i − 2 a_{i-2} ai2
    • 以上所有情况加和,递推关系为: a i = a i − 1 + 2 ∗ a i − 2 a_i=a_{i-1}+2*a_{i-2} ai=ai1+2ai2

解法2:递归

  • 递归问题:求i列道路铺砖的方案数
  • 递归关系:i列道路铺砖的方案数,是i-1列道路铺砖方案数加上2倍的i-2列道路铺砖的方案数(参考上面递推关系的分析方法)
  • 递归出口:0列道路铺砖有1种方案,就是不铺。1列道路铺砖只有1种方案

【注意】:
因为 a i = a i − 1 + 2 a i − 2 > 2 a i − 2 a_i=a_{i-1}+2a_{i-2}>2a_{i-2} ai=ai1+2ai2>2ai2
因此: a 201 > 2 a 199 > 2 2 a 197 > . . . > 2 100 a 1 = 2 100 a_{201}>2a_{199}>2^2a_{197}>...>2^{100}a_1=2^{100} a201>2a199>22a197>...>2100a1=2100,是一个高精度数字。
n最大为250,因此该题结果最大值 a 250 a_{250} a250也一定是一个高精度数字。
因此该题必须使用高精度计算。
估算结果的位数:
a i = a i − 1 + 2 a i − 2 < 3 a i − 1 < 3 2 a i − 2 < . . . < 3 i − 1 a 1 = 3 i − 1 a_i=a_{i-1}+2a_{i-2}<3a_{i-1}<3^2a_{i-2}<...<3^{i-1}a_1=3^{i-1} ai=ai1+2ai2<3ai1<32ai2<...<3i1a1=3i1
所以 a 250 < 3 249 < 3 250 a_{250}<3^{249}<3^{250} a250<3249<3250
3 250 3^{250} 3250的位数 ⌊ l o g 10 3 250 ⌋ + 1 < 250 ∗ l o g 10 3 + 1 < 250 ∗ l o g 10 10 + 1 = 251 \lfloor log_{10}3^{250}\rfloor +1<250*log_{10}3+1<250*log_{10}10+1=251 log103250+1<250log103+1<250log1010+1=251
因此可以把高精度数字的位数设为255。

【题解代码】

解法1:递推

  • 写法1:使用全局变量和函数
#include <bits/stdc++.h>
using namespace std;
#define N 255 //经过估算结果位数不超过251 
void showNum(int a[])
{
    
    
	for(int i = a[0]; i >= 1; --i)
		cout << a[i];
	cout << endl;
}
void setLen(int a[], int i)
{
    
    
	while(a[i] == 0 && i > 1)
		i--;
	a[0] = i;
}
void Add(int a[], int b[]) // a += b
{
    
    
	int c = 0, i;
	for(i = 1; i <= a[0] || i <= b[0]; ++i)
	{
    
    
		a[i] += b[i]+c;
		c = a[i]/10;
		a[i] %= 10;
	}
	a[i] = c;
	setLen(a, i);
}
int main()
{
    
    
	int n, a[255][N] = {
    
    };//a[i]:i列道路铺砖的方案数
	a[0][0] = 1, a[0][1] = 1;//a[0] = 1
	a[1][0] = 1, a[1][1] = 1;//a[1] = 1
	for(int i = 2; i <= 250; ++i)	
	{
    
    //a[i] = a[i-1]+2*a[i-2]
		Add(a[i], a[i-1]);
		Add(a[i], a[i-2]);
		Add(a[i], a[i-2]);
	}
	while(cin >> n)
		showNum(a[n]);
	return 0;
}
  • 写法2:使用类和重载运算符
#include<bits/stdc++.h>
using namespace std;
#define N 255
class HPN
{
    
    
private:
    int a[N];
public:
    HPN()
    {
    
    
        memset(a, 0, sizeof(a));
    }
    HPN(int n)//前提:n小于10
    {
    
    
        memset(a, 0, sizeof(a));
        a[0] = 1;
        a[1] = n;
    }
    int& operator [] (int i)
    {
    
    
        return a[i];
    }
    HPN operator + (HPN b)
    {
    
    
        HPN r;
        int c = 0, i;
        for(i = 1; i <= a[0] || i <= b[0]; ++i)
        {
    
    
            r[i] = a[i] + b[i] + c;
            c = r[i] / 10;
            r[i] %= 10;
        }
        r[i] = c;
        while(r[i] == 0)
            i--;
        r[0] = i;
        return r;
    }
    void show()
    {
    
    
        for(int i = a[0]; i >= 1; --i)
        	cout << a[i];
        cout << endl;
    }
};
int main()
{
    
    
    HPN a[255];//a[i]:i列道路铺砖的方案数 
    a[0] = HPN(1);
	a[1] = HPN(1);
	for(int i = 2; i <= 250; ++i)
        a[i] = a[i-1]+a[i-2]+a[i-2];//由于只重载了+运算符,因此用加法来写递推关系 
    int n;
    while(cin >> n)
        a[n].show();
    return 0;
}

解法2:递归

使用类和重载运算符,记忆化递归

#include<bits/stdc++.h>
using namespace std;
#define N 255
class HPN
{
    
    
private:
    int a[N];
public:
    HPN()
    {
    
    
        memset(a, 0, sizeof(a));
    }
    HPN(int n)//前提:n小于10
    {
    
    
        memset(a, 0, sizeof(a));
        a[0] = 1;
        a[1] = n;
    }
    int& operator [] (int i)
    {
    
    
        return a[i];
    }
    HPN operator + (HPN b)
    {
    
    
        HPN r;
        int c = 0, i;
        for(i = 1; i <= a[0] || i <= b[0]; ++i)
        {
    
    
            r[i] = a[i] + b[i] + c;
            c = r[i] / 10;
            r[i] %= 10;
        }
        r[i] = c;
        while(r[i] == 0)
            i--;
        r[0] = i;
        return r;
    }
    void show()
    {
    
    
        for(int i = a[0]; i >= 1; --i)
        	cout << a[i];
        cout << endl;
    }
};
HPN a[255];//a[i]:i列道路铺砖的方案数    
HPN solve(int i)//求i列道路铺砖的方案数
{
    
    
	if(i == 0 || i == 1)
		return HPN(1); 
	if(a[i][0])//通过看a[i]数字是否设置位数,来判断a[i]是否已经求出
		return a[i];
	else
		return a[i] = solve(i-1) + solve(i-2) + solve(i-2);
}
int main()
{
    
    
    int n;
    while(cin >> n)
    	solve(n).show();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lq1990717/article/details/128710283
今日推荐