蓝桥杯寒假训练----2

大提琴的声音就像一条河,左岸是我无法忘却的回忆,右岸是我值得紧握的璀璨年华,中间流淌的,是我年年岁岁淡淡的感伤。

                                                     李白打酒

话说大诗人李白,一生好饮,幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒 2 斗,他边走边唱:

无事街上走,提壶去打酒。

逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店 mm 次,遇到花 nn 次,已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为 aa,遇花记为 bb。

例如:这一路上,他一共遇到店 55 次,遇到花 1010 次,已知最后一次遇到的是花,他正好把酒喝光了。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

Input

输入一个整数 TT,包括 TT 组数据,每组数据包括遇到店的次数 mm,花的次数 nn。

Output

对于每组数据,输出李白遇到店和花的可能次序的个数。

Example

input

Copy

1
5 10

output

Copy

14
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int ct,T,m,n;
void dfs(int sum,int fg,int store,int flower)
{
    if(store==0&&flower==0&&fg==1)//最后一次遇到的是花
    {
        if(sum==0)//恰好把酒喝光
        {
            ct++;
            return ;
        }
        else
            return ;
    }
    else
    {
        if(store>0&&sum>0)//有酒经过商店
            dfs(sum*2,0,store-1,flower);
        if(flower>0&&sum>0)//有酒经过花店
            dfs(sum-1,1,store,flower-1);
    }
}
int main()
{
    cin>>T;
    while(T--)
    {
        ct=0;
        cin>>m>>n;
        dfs(2,0,m,n);
        cout<

                                                     九宫重排

如下面第一个图的九宫格中,放着 1 到 8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

蓝桥杯寒假训练----2_第1张图片蓝桥杯寒假训练----2_第2张图片我们把第一个图的局面记为:12345678.

把第二个图的局面记为:123.46758

显然是按从上到下,从左到右的顺序记录数字,空格记为句点。

本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出 −1−1。

Input

输入第一行包含九宫的初态,第二行包含九宫的终态。

Output

输出最少的步数,如果不存在方案,则输出 −1−1。

Example

input

Copy

12345678.
123.46758

output

Copy

3
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int fx[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
int jc[]= {1,1,2,6,24,120,720,5040,40320,362880}; //表示阶乘运算的结果
int vis[4000010];
struct node
{
    int now[10];
    int x;
    int bs;
} ks,mb,p;
queue Q;
int cantor(int *s)
{
    int i,j,num=0,temp;
    for(i=0; i<9; i++)
    {
        temp=0;//temp记录当前数位前面的低数位中小于当前位数上的数字的个数
        for(j=i+1; j<9; j++)
            if(s[j]2||y0<0||y0>2)
                continue;
            node q=p;
            q.x=x0*3+y0;
            q.bs++;
            q.now[p.x]=q.now[q.x];
            q.now[q.x]=0;
            t=cantor(q.now);
            if(!vis[t])
            {
                vis[t]=1;
                Q.push(q);
            }
        }
        Q.pop();
    }
    printf("-1\n");
}

                                                         两点

福克斯在玩一款手机解迷游戏,这个游戏叫做"两点"。基础级别的时候是在一个 n×mn×m 单元上玩的。像这样:

每一个单元有包含一个有色点。我们将用不同的大写字母来表示不同的颜色。

这个游戏的关键是要找出一个包含同一颜色的环。看上图中 44 个蓝点,形成了一个环。一般的,我们将一个序列 d1,d2,...,dkd1,d2,...,dk 看成一个环,当且仅当它符合下列条件时:

1. 这 kk 个点不一样,即当 i≠ji≠j 时,didi 和 djdj 不同。

2. kk 至少是 44。

3. 所有的点是同一种颜色。

4. 对于所有的 1≤i≤k−11≤i≤k−1: didi 和 di+1di+1 是相邻的。还有 dkdk 和 d1d1 也应该相邻。单元 xx 和单元 yy 是相邻的当且仅当他们有公共边。

当给出一幅格点时,请确定里面是否有环。

Input

单组测试数据。

第一行包含两个整数 nn 和 mm (2≤n,m≤50)(2≤n,m≤50): 板子的行和列。

接下来 nn 行,每行包含一个有 mm 个字母的串,表示当前行每一个点的颜色。每一个字母都是大写字母。

Output

如果有环输出 Yes,否则输出 No。

Example

input

Copy

3 4
AAAA
ABCA
AADA

output

Copy

No
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
char mp[60][60];
int vis[60][60],fg,n, m;
int fx[] = {0, -1, 0, 1};
int fy[] = {1, 0, -1, 0};

void dfx(int x, int y, char c, int dir)
{
    if(x < 0 || x > n-1 || y < 0 || y > m-1 || mp[x][y] != c)
        return;
    if(vis[x][y])
    {
        fg = 1;
        return;
    }
    vis[x][y] = 1;
    for(int i = 0; i < 4; i++)
    {
        if(dir == 0 && i == 2)
            continue;
        if(dir == 1 && i == 3)
            continue;
        if(dir == 2 && i == 0)
            continue;
        if(dir == 3 && i == 1)
            continue;
        int xx = x + fx[i];
        int yy = y + fy[i];
        dfx(xx, yy, c, i);
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++)
        scanf("%s", mp[i]);
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            if(fg)
                break;
            if(vis[i][j])
                continue;
            dfx(i, j, mp[i][j], -1);
        }
        if(fg)
            break;
    }
    if(fg)
        printf("Yes\n");
    else
        printf("No\n");
    return 0;
}

                                                    大臣的旅费

很久以前,T 王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T 国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J 是 T 国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了 J 最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

聪明的 J 发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第 xx 千米到第 x+1x+1 千米这一千米中(xx 是整数),他花费的路费是 x+10x+10 这么多。也就是说走 11 千米花费 1111,走 22 千米要花费 2323。

J 大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

Input

输入的第一行包含一个整数 nn (0

城市从 1 开始依次编号,1 号城市为首都

接下来 n−1n−1 行,描述 T 国的高速路(T 国的高速路一定是 n−1n−1 条)

每行三个整数 Pi,Qi,DiPi,Qi,Di,表示城市 PiPi 和城市 QiQi 之间有一条高速路,长度为 DiDi 千米 (0

Output

输出一个整数,表示大臣 J 最多花费的路费是多少

Example

input

Copy

5
1 2 2
1 3 1
2 4 5
2 5 4

output

Copy

135
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int mp[30][30],n,P,Q,D,sum;
int main()
{
    cin>>n;
    int ls=n-1;
    memset(mp,inf,sizeof(mp));
    while(ls--)
    {
        cin>>P>>Q>>D;
        mp[P][Q]=mp[Q][P]=D;
    }
    for(int k=1; k<=n; k++)
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if(mp[i][k]!=inf&&mp[k][j]!=inf)
                    mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
            }
        }
    }
    for(int i=1; i<=n; i++)
        for(int j=i+1; j<=n; j++)
            sum=max(sum,mp[i][j]);
    cout<

                                                     Tri Tiling

In how many ways can you tile a 3×n3×n rectangle with 2×12×1 dominoes? Here is a sample tiling of a 3×123×12 rectangle.

Input

Input consists of several test cases followed by a line containing −1−1. Each test case is a line containing an integer 0≤n≤300≤n≤30.

Output

For each test case, output one integer number giving the number of possible tilings.

Example

input

Copy

0
6
10
-1

output

Copy

1
41
571
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int dp[50],n;
int main()
{
    dp[0]=1;
    dp[2]=3;
    for(int i=4; i<=30; i++)
        dp[i]=4*dp[i-2]-dp[i-4];
    while(cin>>n&&n!=-1)
    {
        cout<

                                                01 组成的 N 的倍数

output

standard output

给定一个自然数 N,找出一个 M,使得M>0 且 M 是 N 的倍数,并且 M 的 10 进制表示只包含 0 或 1,求最小的 M。

Input

输入 1个数 N。(1≤N≤106)(1≤N≤106)

Output

输出符合条件的最小的 M。

Examples

input

Copy

1

output

Copy

1

input

Copy

4

output

Copy

100
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
struct node
{
    int x;
    int q;
} p[5000010];
int vis[5000010],n,ct;//vis余数状态0未出现,1出现
void dfs(int y)
{
    int ans=p[y].q;
    if(ans<=0)
    {
        cout<<1;
        return;
    }
    dfs(ans);
    cout< qu;
    p[0].x=1;
    p[0].q=0;
    qu.push(ls1);
    while(!qu.empty())
    {
        ls2=qu.front();
        qu.pop();
        for(int i=0; i<=1; i++)
        {
            ls1.x=ls2.x*10+i;
            ls1.x%=n;//余数
            if(!vis[ls1.x])
            {
                ls1.q=ct;
                vis[ls1.x]=1;
                p[ct].x=i;
                p[ct].q=ls2.q;
                qu.push(ls1);
                if(ls1.x==0)
                {
                    dfs(ct);
                    cout<>n;
    if(n==1)
        cout<<1<

                                                         剪格子

如下图所示,3×33×3 的格子中填写了一些整数。

我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是 6060。

本题的要求就是请你编程判定:对给定的 m×nm×n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。

如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。

如果无法分割,则输出 00。

Input

程序先读入两个整数 m,nm,n 用空格分割 (m,n<10)(m,n<10),表示表格的宽度和高度。

接下来是 mm 行,每行 nn 个正整数,用空格分开。每个整数不大于 1000010000。

Output

输出一个整数,表示在所有解中,包含左上角的分割区可能包含的最小的格子数目。

Example

input

Copy

3 3
10 1 52
20 30 1
1 2 3

output

Copy

3

题解:

题目大体意思是要分成两部分,这两部分数字的和要相等。

背后的意思是 怎么分成两部分。

正常思路是 dfs 上下左右,左上角所在集合标记成 1,一旦标记集合的和是总和的一半,此时实现了 “分开”。在每次“分开”中更新最小的块数。

问题来了。(假设阴影处是最优解)

蓝桥杯寒假训练----2_第3张图片

所以 考虑添加方向

变成 8 个方向

int dir[8][2] = {1, 0, 1, -1, 0, 1, 0, -1, -1, 0, -1, 1, 1, 1, -1, -1};

上下左右,左上 左下 右上 右下

但是会有很多组数据超时

蓝桥杯寒假训练----2_第4张图片

最后考虑,斜着的方向只添加一个,左下(从 0, 0 处划分两块,大体方向是左下,下,右下)

int dx[] = {0, 0, 1, -1, 1};
int dy[] = {1, -1, 0, 0, -1};

又出现新问题了

蓝桥杯寒假训练----2_第5张图片

左下角的没有办法剪,所以说:

虽然这种情况可以搜索到,但是这种情况不是解。

怎么排除这种情况呢

被标记的小块的,看看周围有没有提前被标记了的就行了。(上下左右是否接壤)

蓝桥杯寒假训练----2_第6张图片

左下角的上面和右面都没有接壤,所以没有办法剪下来,所以排除。

大体思路就是这样

#include 
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
const int INF = 0x3f3f3f3f;
int n, m;
int ans = INF;
int e[20][20];
int sum; //总和
int dx[] = {0, 0, 1, -1, 1};
int dy[] = {1, -1, 0, 0, -1};
bool vis[20][20];
bool check() { // 检查有没有斜着蹦出来的
    int flag = 0;
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++) {
            if (vis[i][j]) { // 看看所有被标记点 是不是有斜着的
                flag = 1;
                int k = 0;
                for (k = 0; k < 4; k++) {
                    if (i + dx[k] < 0 || i + dx[k] >= m || j + dy[k] < 0 ||
                        j + dy[k] >= n)
                        continue; // 界外
                    if (vis[i + dx[k]]
                           [j + dy[k]]) { //   试探: i+dx[k]  j+dy[k]
                                          //   (上下左右被标记 ) 就跳出
                        flag = 0;
                        break; //说明它的上下左右至少有一个接壤的
                               //也就是说不能出现斜着蹦出来的
                    }
                }
                if (flag)
                    return false;
            }
        }
    return true;
}
void dfs(int x, int y, int res, int step) { // x,y 标记的和,标记了多少块
    if (res > sum / 2)
        return;
    if (res == sum / 2 && check()) {
        ans = min(ans, step);
        return;
    }
    for (int i = 0; i <= 4; i++) {
        int xx = x + dx[i];
        int yy = y + dy[i];
        if (xx >= m || yy >= n || xx < 0 || yy < 0)
            continue; // 界外
        if (!vis[xx][yy]) {
            vis[xx][yy] = 1;
            dfs(xx, yy, res + e[xx][yy], step + 1);
            vis[xx][yy] = 0;
        }
    }
}
int main() {
    scanf("%d%d", &m, &n);
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++)
            scanf("%d", &e[i][j]), sum += e[i][j];
    if (sum & 1) {
        printf("0\n");
        return 0;
    }
    vis[0][0] = 1;
    dfs(0, 0, e[0][0], 1);
    if (ans == INF)
        printf("0\n");
    else
        printf("%d\n", ans);
    return 0;
}

 

你可能感兴趣的:(蓝桥杯练习)