#YBT整理 递推(三)

重点题目:

1、P1197 :山区建小学

2、P1195 :判断整除

3、P1192 :放苹果

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

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

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

P1195 :判断整除

题目描述

一个给定的正整数序列,在每个数之前都插入+号或一号后计算它们的和。比如序列: 1、2、4共有8种可能的序列:

(+1) + (+2) + (+4) = 7
(+1) + (+2) + (-4) = -1
(+1) + (-2) + (+4) = 3
(+1) + (-2) + (-4) = -5
(-1) + (+2) + (+4) = 5
(-1) + (+2) + (-4) = -3
(-1) + (-2) + (+4) = 1
(-1) + (-2) + (-4) = -7

所有结果中至少有一一个可被整数k整除,我们则称此正整数序列可被k整除。例如上述序列可以被3、5、7整除,而不能被2、4、6、......除。注意: 0、一3、一6、一9... ...都可以认为是3的倍数。

【输入】

输入的第一行包含两个数: N(2 《N 《 10000)和k(2 《k《 100),其中N代表一共有N个数, k代表被除数。第二行给出序列中的N个整数,这些整数的取值范围都0到10000之间(可 能重复)

【输出】

如果此正整数序列可被k整除,则输出YES,否则输出NO。(注意: 都是大写字母)

【输入样例】

3 2
1 2 4

【输出样例】

NO

思路

用a数组存储每一步可能粗线的每一种和,因为k < 100 所以只用开100的就行,存储方式类似于桶。
b数组辅助存储。a[i]就相当于当前操作是否可能出现i,可能为true,不可能为false。每一次更新的时候就从为true的i进行加减操作。具体看代码。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
 long long n;
bool a[1000],b[1000];
 long long k;
int main(){
    cin >> n;
    cin >> k;
    for( long long i = 1;i <= n; i++){
         long long x;
        cin >> x;
        if(i == 1){
            b[x%k] = 1;
             long long y = -x;
            while(y < 0) y += k;
            b[y] = 1;
            for( long long j = 1;j < k; j++){
                a[j] = b[j];
            }
            for(int j = 0;j < k; j++) cout << a[j] << ' ';
            cout << endl;
            continue;
        }
        x %= k;
        memset(b,0,sizeof b);
        for( long long j = 0;j < k; j++){
            if(a[j]){
                b[(j+x) % k] = 1;
                b[(j-x+k) % k] = 1;
            }
        }
        for( long long j = 0;j < k; j++){
            a[j] = b[j];
            cout << a[j] <<  ' ';
        }
        cout << endl; 
    }
    if(a[0] == 1){
        cout << "YES" << endl;
        return 0;
    }
    cout << "NO" << endl;
    return 0;
}

P1196 :踩方格

题目描述

有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:

a、每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;

b、走过的格子立即塌陷无法再走第二次;

c、只能向北、东、西三个方向走;

请问:如果允许在方格矩阵上走n步,共有多少种不同的方案。2种走法只要有一步不一 样,即被认为是不同的方案。

【输入】

允许在方格上行走的步数n(n<=20)。

【输出】

计算出的方案数量。

【输入样例】

2

【输出样例】

7

思路

每次只能往三个方向走,因为是20的数据范围,所以直接暴力dfs

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
int vis[50][50];
int ans = 0;
void dfs(int x,int y,int step){
    if(step == n){
        ans++;
        return;
    }
    if(!vis[x+1][y]){
        vis[x+1][y] = 1;
        dfs(x+1,y,step+1);
        vis[x+1][y] = 0;
    }
    if(!vis[x][y+1]){
        vis[x][y+1] = 1;
        dfs(x,y+1,step+1);
        vis[x][y+1] = 0;
    }
    if(!vis[x][y-1]){
        vis[x][y-1] = 1;
        dfs(x,y-1,step+1);
        vis[x][y-1] = 0;
    }
}
int main(){
    cin >> n;
    vis[0][25] = 1;
    dfs(0,25,0);
    cout << ans << endl;
    return 0;
}

P1197 :山区建小学

题目描述

政府在某山区修建了一一条道路,恰好穿越总共m个村庄的每个村庄-一次,没有回路或交叉,任意两个村庄只能通过这条路来往。已知任意两个相邻的村\(d_{i}\)(为正整数),其中,0<i<m。为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设0<n≤m<500)。请根据给定的m、n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值。

【输入】

第1行为m和n,其间用空格间隔

第2行为m一1个整数,依次表示从一端到另一端的相邻村庄的距离,整数之间以空格间隔。例如:

10 3
2 4 6 5 2 4 3 1 3

表示在10个村庄建3所学校。第1个村庄与第2个村庄距离为2,第2个村庄与第3个村庄距离为4,第3个村庄与第4个村庄距离为6,.... 第9个村庄到第10个村庄的距离为3。

【输出】

各村庄到最近学校的距离之和的最小值。

【输入样例】

10 2
3 1 3 1 1 1 1 1 3

【输出样例】

18

思路

就先初始化几个数组:dis[i][j]表示i到j的距离,s[i][j]表示从i到j建一所学校的最短花费(可以证明学校一定要建立在ij的正中间),最后上动态规划:f[i][j]表示前i个学校建立j所学校的最小化费,每次从小到大枚举k。

\[f[i][j] = min(f[i][j],f[k][j-1] + s[k+1][i]) \]

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m;
int dis[600][600];
int s[600][600];
int f[600][600];
int add[600];
int cnt_dis(int x,int y){
    int tot = 0;
    int mid = (x+y) >> 1;
    for(int i = x;i <= y; i++){
        tot += dis[mid][i];
    }
    return tot;
}
int main(){
    cin >> n;
    cin >> m;
    for(int i = 2;i <= n; i++){
        int x;
        cin >> x;
        add[i] = add[i-1] + x;
    }
    for(int i = 1;i <= n; i++){
        for(int j = i;j <= n; j++){
            dis[i][j] = dis[j][i] = add[j] - add[i];
        }
    }
    for(int i = 1;i <= n; i++){
        for(int j = i;j <= n; j++){
            s[i][j] = s[j][i] = cnt_dis(i,j);
        }
    }
    memset(f,1e9+7,sizeof f);
    f[0][0] = 0;
    for(int i = 1;i <= n; i++){
        for(int j = 1;j <= m; j++){
            if(i < j) {f[i][j] = 0;continue;}
            for(int k = j-1;k <= n; k++){
                f[i][j] = min(f[i][j],f[k][j-1]+s[k+1][i]);
            }
        }
    }
    cout << f[n][m] << endl;
    return 0;
}
posted @ 2020-03-12 12:05  CYC的幸福生活  阅读(292)  评论(0编辑  收藏  举报