第二届“传智杯”全国大学生IT技能大赛(决赛)(A~D题解)

注意:代码不保证一定正确,因为这些题目在补题的时候无法在洛谷提交,当然思路是没有问题的(白嫖题解的思路

T130013 游园会盖章

题目链接
这题就是个水题,哎怪我读错题了

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
void fre() { freopen("A.txt","r",stdin);} //freopen("Ans.txt","w",stdout); }
using namespace std;
char ar[20][55] = {
"...........................,]]OOO@@@@OOO]`........",
"....................,]OO@@@@@@@@@@@@@@@@@@@@O`....",
"................./O@@@@@@@@@@@@@@@@@@@@@@@@@@@@^..",
"............../O@@@@@@@@@@@@@@@OOOOOOO@@@@@@@@@@@.",
"..........,/@@@@@@@@@@@@O/[.............[O@@@@@@@\\",
"........,O@@@@@@@@@@O/`..................,O@@@@@@O",
".......O@@@@@@@@@O`......]OO@@@O\\`........O@@@@@@@",
".....,O@@@@@@@@/`.....]O@@@@@@@@@@^.......O@@@@@@@",
"...,/@@@@@@@O/...../@@@@@@@@@@@@@@O....../@@@@@@@0",
"..=@@@@@@@O`...../@@@@@@@@@@@@@@@@^.....O@@@@@@@O.",
"./@@@@@@@/......O@@@@@@@@@@@@@@@O`..../@@@@@@@@O..",
"=@@@@@@@O......O@@@@@@@@@@@@@@@^....O@@@@@@@@@O...",
"O@@@@@@@^.....=@@@@@@@@@@@@@O[..../@@@@@@@@@O`....",
"@@@@@@@O.......\\@@@@@@@@O[...../O@@@@@@@@@O`......",
"@@@@@@@@^.........[`.......]OO@@@@@@@@@@O`........",
"O@@@@@@@@O\\............]/@@@@@@@@@@@@O/...........",
"=@@@@@@@OOOoo`........O@@@@@@@@@@@@/`.............",
"..\\OOOOO*,`*..........O@@@@@@@@@O`................",
".....,[[..............O@@@@@@O`...................",
"......................O@@@@@@O....................",
};
char maze[1005][2005];


int main()
{
    /* fre(); */
    int n, h, w;
    scanf("%d %d %d", &n, &h, &w);
    int t, x, y;
    memset(maze, '.', sizeof(maze));
    while(n --)
    {
        scanf("%d %d %d", &x, &y, &t);
        if(t == 0)
        {
            for(int i = x; i < x + 20; i ++)
                for(int j = y; j < y + 50; j ++)
                    if(i < h && j < w && ar[i - x][j - y] != '.') 
                        maze[i][j] = ar[i - x][j - y];
        }
        else
        {
            for(int i = x; i < x + 20; i ++)
                for(int j = y; j < y + 50; j ++)
                    if(i < h && j < w && ar[19 - i + x][49 - j + y] != '.')
                        maze[i][j] = ar[19 - i + x][49 - j + y];
        }
    }
    for(int i = 0; i < h; i ++)
    {
        for(int j = 0; j < w; j ++)
            printf("%c", maze[i][j]);
        printf("\n");
    }

    return 0;
}

T130014 补刀

题目链接

思路

  • 分析:这一题直接分类讨论就行了
  1. 如果 当前人物 攻击为0,那么一定不能杀死怪物
  2. 如果 防御塔的攻击为0,那么人物移动可以杀死怪物
  3. 在防御塔把怪物击杀前,必须是人物给他致命一击,我们考虑如果人物不攻击,假设防御塔需要 x次攻击才可以杀死怪物,因为人物的攻速于防御塔的攻速相同,并且人物可在刚开始在防御塔攻击钱,先进性攻击,因此防御塔攻击x-1次的话,人物最多可以攻击 x次,防御塔攻击x-1次还没把怪物杀死,此时假设怪物的剩下的血量为t,人物的攻击为s,如果人攻击x次造成的伤害为sum = x*s如果sum >= t 的话就一定可以杀死怪物,小于的话就会被防御塔的下一次攻击给杀死。

注意:0%0是错的❌

代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
using namespace std;
const int INF = 0x3f3f3f3f;
#define ll long long 

ll h, x, y;
bool judge(ll num)
{
    ll l = 1, r = num + 1;
    int ans = 0;
    while(l <= r)
    {
        ll md = (l + r) >> 1;
        if(num * x + md * y >= h)
        {
            r = md - 1;
            ans = 1;
        }
        else
        {
            l = md + 1;
        }
    }
    return ans = 1;
}

int main()
{
    /* fre(); */
    int t;
    scanf("%d", &t);
    while(t --)
    {
        scanf("%lld %lld %lld", &h, &x, &y);
        if(x == 0 && y == 0)
        {
            printf("No\n");
            continue;
        }
        else if(x == 0)
        {
            printf("Yes\n");
            continue;
        }

        ll r = h/x; 
        if(r * x != h)
            r ++;
        r --;

        int ans = 0;
        if(r + 1 >= ceil((double)(h - r * x)/ y))
            ans = 1;
        if(ans)
            printf("Yes\n");
        else
            printf("No\n");
    }

    return 0;
}

T130015 建设岛屿

题目链接

思路

题意:让我们建设岛屿,形状规则如下图,之后给我了一个n*m的地图,我们我们可以改这个地图的高度k次,每一改变是使某个格子中的数字(代表高度)+1,注意我们只能在原来的数(高度)上增加,不能减少,问我们在这个地图上最大能建造多大的 如下图所示的”回字形图形“
第二届“传智杯”全国大学生IT技能大赛(决赛)(A~D题解)_第1张图片

  • 分析:由于题目给的数据 1 = < n , m < = 100 1=1=<n,m<=100,我们可以暴力枚举一下,我们第一层循环从大到小枚举可以修的层数r,对每一个相应的层数,我们可以所有的状态,在检查某个状态是否符合题意的时候,并统计最少需要的更改地形的次数,如果次数>k或者该状态不符合题意,直接break,进行下一个状态
  • 算法复杂度勉强算是 O n 5 On^5 On5,因为 r 很大的时候,其实可枚举的状态很少的,而当r很小的时候,虽然需要枚举的状态多但是,但是遍历判断状态判断的格子少

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
using namespace std;

int mp[105][105];

int main()
{
    /* fre(); */
    int t;
    scanf("%d", &t);
    while(t --)
    {
        int m, n, k;
        scanf("%d %d %d", &m, &n, &k);
        for(int i = 1; i <= m; i ++)
            for(int j = 1; j <= n; j ++)
                scanf("%d", &mp[i][j]);
        int r = min(m, n);
        while(r)
        {
            int flag = 0;
            for(int i = r; i <= m - r + 1; i ++) 
            {
                for(int j = r; j <= n - r + 1; j ++)
                {
                    flag = 1; int cnt = 0;
                    for(int a = i - r + 1; a <= i + r - 1; a ++)    
                    {
                        for(int b = j - r + 1; b <= j + r - 1; b ++)
                        {
                            int lv = r - max(abs(a - i), abs(b - j));
                            if(mp[a][b] > lv)
                            {
                                flag = 0;
                                break;
                            }
                            cnt += (lv - mp[a][b]);
                        }
                        if(! flag)
                            break;
                    }
                    if(cnt > k)
                        flag = 0;
                    if(flag)
                    {
                        printf("%d\n", r);
                        break;
                    }
                }
                if(flag)
                    break;
            }
            if(flag)
                break;
            r --;
        }
        if(r == 0)
            printf("0\n");
    }

    return 0;
}

T130016 传送门

题目链接

思路

  • 题意:给我一个各个点相互联通的无向图,我们可以选择在这个无向图中的两点假设一个传送门,使这两个点的距离变为0,当这两个点的距离为0之后,这样就有可能影响其他点对点之间的最短距离,问但我在任意点对之间架设一个传送门之后,任意点对之间的最短路距离之和最小为多少?

  • 分析:这一题,题目已经给了提升,任意点对,能求任意点对点之间的最短距离只有floyed算法了,当时咋没看出来呢 ,用floyed跑完多元最短路之后( O ( n 3 ) O(n^3) O(n3),剩下就是暴力枚举 任意一个点对设为(i , j)在这个点对上架设传送门,这里复杂度为 O ( n 2 ) O(n^2) O(n2),在假设个传送门之后,我们考虑,除了(i,j)点对之外,枚举其他点对设为(a,b),这里复杂度为 O ( n 2 ) O(n^2) O(n2),会收到这个传送门的什么影响呢?设一个点对(x,y)在跑完floyed之后对最短路距离为dp[x][y] == dp[y][x],,,,我考虑如果a 到b点点最短路不经过i-j这一边的话,那么a到b之间的最短路距离是不会被影响的,反之如果经过了i-j这条路的化(经过的情况可以是 a-i-j-b、a-j-i-b),那么a到b之间的距离肯定会被影响,这个时候a到b之间的最短路距离是min(dp[a][b], min(dp[a][i] + dp[j][b], dp[a][j] + dp[i][b]))

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define INF 0x3f3f3f3f
using namespace std;
const int mxn = 105;
int dp[mxn][mxn];


int main()
{
    /* fre(); */
    int n, m; 
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            if(i == j) dp[i][j] = 0;
            else dp[i][j] = INF;
    int u, v, w;
    for(int i = 0; i < m; i ++)
    {
        scanf("%d %d %d", &u, &v, &w);
        //建立双向边
        dp[u][v] = w;
        dp[v][u] = w;
    }
    //floyed 算法
    for(int k = 1; k <= n; k ++)
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= n; j ++)
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
     
    //假设假设建立传送门的点对为(i,j)(默认j > i),枚举减少的距离任意一个点对点(a, b)(这里默认b > a)距离为
    int ans = INF, res;
    for(int i = 1; i < n; i ++)
        for(int j = i + 1; j <= n; j ++)
        {
            res = 0;
            for(int a = 1; a < n; a ++)
                for(int b = a + 1; b <= n; b ++)
                    if(a != i || b != j)
                        res += min(dp[a][b], min(dp[a][i] + dp[j][b], dp[a][j] + dp[i][b]));     
            ans = min(ans, res);
        }
    printf("%d\n", ans);

    return 0;
}

你可能感兴趣的:(比赛补题总结)