Contest 2050 and Codeforces Round #718 (Div. 1 + Div. 2) A-D

本场链接:https://codeforces.ml/contest/1517

B. Morning Jogging-贪心


Problem

给出n+1个点,编号从0-n,相邻两个点i,i+1之间有m条边,有m个人从0号点出发到n号点,每条边只能被一个人走,一个人的疲惫程度时这个人所走边权值的最小值。问m个人疲惫程度和最小时多少。

Solution

先对每个点连接的m条边由小到大排序,每次取同一列中最小的值,找到其所在行,对于其它行就取这行的最大值。为了方便,每一行用两个指针指向第一列和最后一列,也就相当于一个指向了最小值,一个指向了最大值。

用样例1来看:

Code

#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
const int N = 2e6+7;
const int mod = 1e9+7;
const ll ds = 1e15;
const double eps = 1e-8;
 
using namespace std;
 
int a[105][105],ans[105][105],jz[105][2];
void solve(){  
    int n,m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            cin >> a[i][j];
        }
        jz[i][0] = 1;
        jz[i][1] = m;
        sort(a[i]+1,a[i]+m+1);
    }
    for(int i = 1; i <= m; i++){
        int mmin = a[1][jz[1][0]],xb = 1;
        for(int j = 1; j <= n; j++){
            if(a[j][jz[j][0]] < mmin){
                mmin = a[j][jz[j][0]];
                xb = j;
            }
        }
        for(int j = 1; j <= n; j++){
            if(j == xb){
                ans[j][i] = a[j][jz[j][0]];
                jz[j][0]++;
            }
            else ans[j][i] = a[j][jz[j][1]],jz[j][1]--;
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            cout << ans[i][j] << " ";
        }
        puts("");
    }
}
 
int main(){
    int t;
    cin >> t;
    while(t--)
        solve();
    //system("pause");
    return 0;
}

C. Fillomino 2-DFS


Problem

给出一个n*n的矩阵,对角线上放1-n的一个排列,然后要将对角线及以下部分分块,每一块内的数字必须相同,并且块的大小要和数字相同。问能否构造出来。

Solution

首先容易想到的是一定能够构造出来的,然后对于对角线上的每个数为起点进行dfs,优先向左填,如果不能填再向下填,还不行就向右填。

Code

#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
const int N = 2e6+7;
const int mod = 1e9+7;
const ll ds = 1e15;
const double eps = 1e-8;
 
using namespace std;
 
int a[505][505],n;
void dfs(int r,int c,int num){
    //cout << r << " " << c << endl;
    if(num >= a[r][c]) 
        return;
    if(r <= 0 || r > n || c <= 0 || c > r)
        return;
    if(!a[r][c-1] && c >= 2){
        a[r][c-1] = a[r][c];
        dfs(r,c-1,num+1);
    }
    else if(!a[r+1][c] && r < n){
        a[r+1][c] = a[r][c];
        dfs(r+1,c,num+1);
    }
    else if(!a[r][c+1] && c < r && r <= n){
        a[r][c+1] = a[r][c];
        dfs(r,c+1,num+1);
    }
}
 
void solve(){  
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i][i];
    }
    for(int i = 1; i <= n; i++){
        dfs(i,i,1);
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= i; j++){
            cout << a[i][j] << " ";
        }
        puts("");
    }
}
 
int main(){
    // int t;
    // cin >> t;
    // while(t--)
        solve();
    //system("pause");
    return 0;
}

D. Explorer Space-DP


Problem

给出n*m的矩阵,每个点和它右边相邻的点有一条无向边,和它下面相邻的点有一条无向边,对于每一个点,求从这个点走k步还回到这个点的最短距离,注意走过的点还可以走。

Solution

如果k为奇数的话是一定不能回到最初位置的,所有直接看k为偶数的情况。

首先我们先找到k/2步能够走的最短距离是多少,然后原路返回就是走k步的最短距离,因为走完k/2步不可能还有其它更短的距离道达最初位置,因为从最初位置走k/2已经是最短距离了,这就矛盾了呀!

Code

#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
const int N = 2e6+7;
const int mod = 1e9+7;
const ll ds = 1e15;
const double eps = 1e-8;
 
using namespace std;
 
ll ans[505][505],dp[505][505][50],a[505][505][5];
void solve(){
    int n,m,k;
    cin >> n >> m >> k;
    //memset(dp,0x3f3f3f3f,sizeof(dp));
    for(int i = 1; i <= n; i++){
        for(int j = 1; j < m; j++){
            dp[i][j][0] = 0;
            cin >> a[i][j][0];
            a[i][j+1][1] = a[i][j][0];
        }
    }
    for(int i = 1; i < n; i++){
        for(int j = 1; j <= m; j++){
            dp[i][j][0] = 0;
            cin >> a[i][j][2];
            a[i+1][j][3] = a[i][j][2];
        }
    }
    if(k&1) {
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                cout << "-1 ";
            }
            puts("");
        }
        return;
    }
    k /= 2;
    for(int i = 1; i <= k; i++){
        for(int j = 1; j <= n; j++){
            for(int l = 1; l <= m; l++){
                dp[j][l][i] = 0x3f3f3f3f3f;
                if(j != 1){
                    dp[j][l][i] = min(dp[j][l][i],dp[j-1][l][i-1]+a[j][l][3]);
                }
                if(l != 1){
                    dp[j][l][i] = min(dp[j][l][i],dp[j][l-1][i-1]+a[j][l][1]);
                }
                if(j != n){
                    dp[j][l][i] = min(dp[j][l][i],dp[j+1][l][i-1]+a[j][l][2]);
                }
                if(l != m){
                    dp[j][l][i] = min(dp[j][l][i],dp[j][l+1][i-1]+a[j][l][0]);
                }
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            cout << 2*dp[i][j][k] << " ";
        }
        puts("");
    }
}
 
int main(){
    // int t;
    // cin >> t;
    // while(t--)
        solve();
    //system("pause");
    return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值