#YBT整理 递推(二)

重点题目:

1、P1197 :山区建小学

2、P1195 :判断整除

3、P1192 :放苹果

4、P1312 :【例3.4】昆虫繁殖

5、P1313 :【例3.5】位数问题

6、P1188 :菲波那契数列(2)

P1189:Pell数列

题目描述

\(Pell数列|a_{1},a_{2},a_{3},...的定义是这样的,a1=1,a_{2}=2,\cdots,a_{n}=2a_{n-1}+a_{n-2}(n>2)。给出一个正整数k,要求Pell数列的第k项模上32767是多少。\)

【输入】

第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括--个正整数k(1≤k<1000000)。

【输出】

n行,每行输出对应-一个输入。输出应是一一个非负整数。

【输入样例】

2
1
8

【输出样例】

1
408

思路

还是用的矩阵乘法。

代码

#include "iostream"
#include "cstdio"
#include "algorithm"
#include "cstring"
#include "string"
#include "cmath"
#define int long long
using namespace std;

const int p = 32767;
int n,a,b;

struct matrix{
	int a[4][4]={};
	void print(){
		for(int i = 0;i < 2; i++){
			for(int j = 0;j < 2; j++){
				cout << a[i][j] << ' ';
			}
			cout << endl;
		}
	} 
}in,e;

matrix operator *(matrix &a,matrix &b){
		matrix c;
		for(int i = 0;i < 2; i++){
			for(int j = 0;j < 2; j++){
				for(int k = 0;k < 2; k++){
					(c.a[i][j] += a.a[i][k] * b.a[k][j] %p) %=p;
				}
			}
		}
		return c;
}

matrix Pow(matrix a,int x){
	matrix tot = e;
	while(x){
		if(x & 1) tot = a * tot;
		a = a * a;
		x >>= 1;
	}
	return tot;
}

signed main(){
    int t;
    cin >> t;
    while(t--){
        cin >> n ;
        a = 2,b = 1; 
        
        e.a[0][0] = 1;e.a[0][1] = 1;
        
        in.a[0][0] = 0; in.a[0][1] = b;
        in.a[1][0] = 1; in.a[1][1] = a;

        matrix ans = Pow(in,n);
        
        int x = ans.a[1][1];
        cout << x << endl;
        }
	return 0;
}

P1190 :上台阶

看上面!

P1191 :流感传染

题目描述

有一批易感人群住在网格状的宿舍区内,宿舍区为n*n的矩阵,每个格点为一个房间,房间里可能住人,也可能空着。在第一天,有些房间里的人得了流感,以后每天,得流感的人会使其邻居传染上流感,(已经得病的不变) ,空房间不会传染。请输出第m天得流感的人数。

【输入】

第一行一个数字n, n不超过100,表示有n*n的宿舍房间。

接下来的n行,每行n个字符,’'表示第一天该房间住着健康的人, #表示该房间空着,'@' 表示第一天该房间住着得流感的人。

接下来的一行是一个整数m, m不超过100。

【输出】

输出第m天,得流感的人数。

【输入样例】

5
....#
.#.@.
.#@..
#....
.....
4

【输出样例】

16

思路

同上面

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
long long n,m;
long long ans;
long long a[200][200],b[200][200];
long long mov[8][2] = {0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,1,-1,-1};
int main(){
    cin >> n;
    for(long long i = 1;i <= n; i++){
        for(long long j = 1;j <= n; j++){
            char c;
            cin >> c;
            if(c == '#')
                a[i][j] = -1;
            if(c == '@')
                a[i][j] = 1;
        }
    }
    // for(long long i = 1;i <= n; i++){
    //     for(long long j = 1;j <= n;j++){
    //         cout << a[i][j] << ' ';
    //     }
    //     cout << endl;
    // }
    cin >> m;
    for(long long k = 1;k < m; k++){
        for(long long i = 1;i <= n; i++){
            for(long long j = 1;j <= n; j++){
                if(a[i][j] == -1){
                    b[i][j] = -1;
                    continue;
                }
                b[i][j] = a[i][j];
                for(long long l = 0;l < 4; l++){
                    if(a[i+mov[l][0]][j+mov[l][1]] != -1){
                        b[i][j] += a[i+mov[l][0]][j+mov[l][1]];
                    }
                }
                if(b[i][j] > 0) b[i][j] = 1;
            }
        }
        for(long long i = 1;i <= n; i++){
            for(long long j = 1;j <= n; j++){
                a[i][j] = b[i][j];
                // cout << b[i][j] << " ";
            }
            // cout << endl;
        }
        // cout << endl;
    }
    for(long long i = 1;i <= n; i++){
        for(long long j = 1;j <= n; j++){
            if(a[i][j] > 0) ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

P1192 :放苹果

题目描述

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法? (用K表示) 5,1,1和1, 5,1是同一种分法。

【输入】

第一行是测试数据的数目t (0<=t<20) 。以下每行均包含二个整数M和N,以空格分开。

【输出】

对输入的每组数据M和N,用一行输出相应的K。

【输入样例】

1
7 3

【输出样例】

8

思路

f[i][j]表示前i个盘子里面放j个苹果的数量,状态转移公式:

\[f[i][j] = f[i][j-1] + [i-j][j] \]

解释:因为允许有空盘子存在,所以递归分为两种情况:有一个空盘子和没有空盘子

有一个空盘子就是f[i][j-1],没有空盘子就是先往每个空盘子里面放一个,再把剩下的i-j个苹果放到j个空盘子里面,就是f[i-j][j]。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[12][12];
int main()
{
    int n,m,t;
    cin>>t;

    while(t>0)
    {
        --t;
        cin>>m>>n;
        a[0][0]=1;
        for(int i=0;i<=m;++i )
        for(int j=1;j<=n;++j)
           {

               if(i<j)   a[i][j]=a[i][i];
               else      a[i][j]=a[i][j-1]+a[i-j][j];
           }
           cout<<a[m][n]<<endl;
    }
    return 0;

}

P1193 :吃糖果

魔改斐波那契。

P1194 :移动路线

题目描述

X桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格的坐标为(m,n)。
小明是个调皮的孩子,一天他捉来一只蚂蚁,不小心把蚂蚁的右脚弄伤了,于是蚂蚁只能向上或向右移动。小明把这只蚂蚁放在左下角的方格中,蚂蚁从左下角的方格中移动到右上角的方格中,每步移动一个方格。蚂蚁始终在方格矩阵内移动,请计算出不同的移动路线的数目。

对于1行1列的方格矩阵,蚂蚁原地移动,移动路线数为1;对于1行2列(或2行1列)的方格矩阵,蚂蚁只需一次向右 (或向上)移动,移动路线数也为.....对于一个2行3列的方格矩阵,如下图所示:

【输入】

输入只有一行,包括两个整数m和n (0 《m+ns20),代表方格矩阵的行数和列数,m、之间用空格隔开。

【输出】

输出只有一行,为不同的移动路线的数目。

【输入样例】

2 3

【输出样例】

3

思路

\[f[i][j] = f[i-1][j] + f[i][j-1]; \]

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int m,n;
int f[20][20];
int main(){
    cin >> m >> n;
    for(int i = 1;i <= n; i++) f[1][i] = 1;
    for(int j = 1;j <= m; j++) f[j][1] = 1;
    for(int i = 2;i <= m; i++){
        for(int j = 2;j <= n; j++){
            f[i][j] = f[i][j-1] + f[i-1][j];
        }
    }
    cout << f[m][n] << endl;
    return 0;
}
posted @ 2020-03-12 12:03  CYC的幸福生活  阅读(605)  评论(0编辑  收藏  举报