十一届蓝桥杯(7月)

1.走方格

题目

在平面上有一些二维的点阵。

这些点的编号就像二维数组的编号一样,从上到下依次为第 1 至第 n 行,从左到右依次为第 1 至第 m 列,每一个点可以用行号和列号来表示。

现在有个人站在第 1 行第 1 列,要走到第 n 行第 m 列。

只能向右或者向下走。

注意,如果行号和列数都是偶数,不能走入这一格中。

问有多少种方案。

输入格式

输入一行包含两个整数 n,m。

输出格式

输出一个整数,表示答案。

数据范围

1≤n,m≤30

输入样例1:

3 4

输出样例1:

2

输入样例2:

6 6

输出样例2:

0

/*
1.特判
2.遍历dfs  
   dfs:
   1.判断出界
   2.向右向下走
   3.判断是否走完
   4.走完+1
3.暴搜会超时
4.采用记忆化搜索或者DP

*/


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

int n,m,res;
int f[31][31];  //记忆化数组

int dfs(int x,int y)
{
    if(x > n || y > m) return 0;
    if(x & 1 || y & 1)
    {
        if(f[x][y]) return f[x][y];
        if(x < n) f[x][y] += dfs(x + 1,y);
        if(y < m) f[x][y] += dfs(x,y + 1);
    }
    return f[x][y];
}

int main()
{
    cin >> n >> m;
    //if(n % 2 == 0 && m % 2 == 0) cout << 0 <<endl;
    f[n][m] = n & 1 || m & 1;
    cout << dfs(1,1);
    return 0;
}
DP代码
分析

在这里插入图片描述

#include <stdio.h>

int n, m;
int f[31][31];

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ ) f[i][1] = 1; // 边界 f[i][1] 特判为 1
    for (int j = 1; j <= m; j ++ ) f[1][j] = 1; // 边界 f[1][j] 特判为 1
    for (int i = 2; i <= n; i ++ )              // 枚举 i
        for (int j = 2; j <= m; j ++ )          // 枚举 j
            if (i & 1 || j & 1)                 // 如果 i, j 中有一个是奇数
                f[i][j] = f[i - 1][j] + f[i][j - 1]; // 那么进行状态转移
    printf("%d\n", f[n][m]); // 转移后 f[n][m] 即为答案
    return 0;
}

作者:垫底抽风
链接:https://www.acwing.com/solution/content/15937/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.整数拼接(。。。)

题目

给定一个长度为 n 的数组 A1,A2,⋅⋅⋅,An。

你可以从中选出两个数 Ai 和 Aj(i 不等于 j),然后将 Ai 和 Aj 一前一后拼成一个新的整数。

例如 12 和 345 可以拼成 12345 或 34512。

注意交换 Ai 和 Aj 的顺序总是被视为 2 种拼法,即便是 Ai=Aj 时。

请你计算有多少种拼法满足拼出的整数是 K 的倍数。

输入格式

第一行包含 2 个整数 n 和 K。

第二行包含 n 个整数 A1,A2,⋅⋅⋅,An。

输出格式

一个整数代表答案。

数据范围

1≤n≤105,
1≤K≤105,
1≤Ai≤109

输入样例:

4 2
1 2 3 4

输出样例:

6

分析

暴搜超时,优化DP
https://www.acwing.com/solution/content/15969/

代码

3.网络分析

题目

小明正在做一个网络实验。

他设置了 n 台电脑,称为节点,用于收发和存储数据。

初始时,所有节点都是独立的,不存在任何连接。

小明可以通过网线将两个节点连接起来,连接后两个节点就可以互相通信了。

两个节点如果存在网线连接,称为相邻。

小明有时会测试当时的网络,他会在某个节点发送一条信息,信息会发送到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接或间接相邻的节点都收到了信息。

所有发送和接收的节点都会将信息存储下来。

一条信息只存储一次。

给出小明连接和测试的过程,请计算出每个节点存储信息的大小。

输入格式

输入的第一行包含两个整数 n,m,分别表示节点数量和操作数量。

节点从 1 至 n 编号。

接下来 m 行,每行三个整数,表示一个操作。

如果操作为 1 a b,表示将节点 a 和节点 b 通过网线连接起来。当 a = b 时,表示连接了一个自环,对网络没有实质影响。
如果操作为 2 p t,表示在节点 p 上发送一条大小为 t 的信息。

输出格式

输出一行,包含 n 个整数,相邻整数之间用一个空格分割,依次表示进行完上述操作后节点 1 至节点 n 上存储信息的大小。

数据范围

1≤n≤10000,
1≤m≤105,
1≤t≤100

输入样例1:

4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1

输出样例1:

13 13 5 3

分析

https://www.acwing.com/solution/content/15945/
并查集和树形DP

代码
/*
1.输入n,m  节点数量和操作数量  1≤n≤10000
2.输入m行:
x x x  

3.输入的过程就操作
    在于这个操作:
    1  联通
    2  发送信息
    
    并查集和树形DP
    
    
4.对每一个节点进行  + 信息
5.输出每一个节点的信息数量

*/
/*
1.输入n,m  节点数量和操作数量  1≤n≤10000
2.输入m行:
x x x  

3.输入的过程就操作
    在于这个操作:
    1  联通
    2  发送信息
    
    并查集和树形DP
    
    
4.对每一个节点进行  + 信息
5.输出每一个节点的信息数量

*/

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

const int N = 200010, M = N << 1;

int h[N],e[M],ne[M],idx;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

int n,m;
int p[N];

int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int f[N];

void dfs(int u,int fa)
{
    f[u] += f[fa];  //把父节点的值下放到子节点
    for(int i = h[u];~i;i = ne[i])
    {
        int j = e[i];
        dfs(j,u);
    }
}


int main()
{
    memset(h,-1,sizeof h);
    
    cin >> n >> m;
    for(int i = 1;i <= n * 2;i++) p[i] = i;   //p 是指的pre  前一个的意思
    
    int root  = n + 1;
    while(m--)
    {
        int op,a,b;
        cin >> op >> a >> b;
        if(op == 1)
        {
            a = find(a);
            b = find(b);
            if(a != b)
            {
                p[a] = p[b] = root;  //新建一个节点,把a和b归类
                add(root,a);
                add(root,b);
                root++;
            }
        }
        else
        {
            a = find(a);
            f[a] += b;
        }
    }
    
    //最后对我们所构造出来的一堆树DP(只是遍历一下)
    //把每个点的权值下放到子树中的所有节点中
    for(int i = n + 1;i < root;i++)  
        if(p[i] == i)   //这里表示是根节点。。。
            dfs(i,0);
        
    for(int i = 1;i <= n;i++)
        cout << f[i] << ' ';
    return  0; 
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值