ACM-ICPC North America Qualifier Contest 2018

ACM-ICPC North America Qualifier Contest 2018

A. Bingo Ties

题意: 有一个新bing游戏,给定n个 5 ∗ 5 5*5 55的网格,每次玩家给定一组数列,如果这组数列包含了某2个网格某2行的所有数字,那么就会bingo。要求打印使得产生bingo的字典序最小的2个网格的序号。

题解: 通过分析可以知道,能够产生bingo的2行至少要有一个数字相同,因此如果2行数字存在至少一个数字相同,那么这2行对应的网格可能产生bingo。但是,可能出现一种情况使得在2行数字正在匹配的过程中,出现第3个网格的某一行先和2行数字的其中一行匹配上的情况,需要特判下。特判的方式如下:2行数字还没有bingo时会存在t的数字,那么如果第3个网格的某一行被完全包含于这t个数字的话,就会提前bingo。

代码:

#include <bits/stdc++.h>

using namespace std;

int const N = 2e5 + 10;
typedef long long LL;
typedef pair<int, int> PII;

int n, m, T;
struct Mat {
    int g[110][100];
}gra[110];
int pos1, pos2;

bool judge2(int x, int l1, int p1, int y, int r1, int p2, int t) {
    set<int> s;
    for (int i = 1; i <= 5; ++i) {
        if (gra[x].g[l1][i] != t) s.insert(gra[x].g[l1][i]);
        if (gra[y].g[r1][i] != t) s.insert(gra[y].g[r1][i]);
    }
    if (s.size() < 5) return false;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= 5; ++j) {
            int cnt = 0;
            for (int k = 1; k <= 5; ++k) 
                if (s.count(gra[i].g[j][k])) cnt++;
            if (cnt == 5) return true; 
        }
    return false;
}

bool judge(int x, int line1, int y, int line2) {
    for (int i = 1; i <= 5; ++i) 
        for (int j = 1;  j <= 5; ++j) 
            if (gra[x].g[line1][i] == gra[y].g[line2][j]) {
                int pos1 = i, pos2 = j;
                if (!judge2(x, line1, pos1, y, line2, pos2, gra[x].g[line1][pos1])) return true;
            }
    return false;
}

int main() {
    // freopen("in.txt", "r", stdin);
    cin >> n;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= 5; ++j) {
            for (int k = 1; k <= 5; ++k)
                cin >> gra[i].g[j][k];
        }

    int flg = 0;
    for (int i = 1; i <= n; ++i) 
        for (int j = i + 1; j <= n; ++j) 
            for (int l1 = 1; l1 <= 5; ++l1) 
                for (int r1 = 1; r1 <= 5; ++r1) 
                        if (judge(i, l1, j, r1)) {
                            flg  = 1;
                            cout << i << " " << j << endl;
                            return 0;
                        }
    if (!flg) cout << "no ties";
    return 0;
}

B. Das Blinkenlights

**题意: ** 签到

题解: 签到

代码:

#include <bits/stdc++.h>

using namespace std;

int const N = 2e5 + 10;
typedef long long LL;
typedef pair<int, int> PII;

int n, m, T;

int gcd(int a, int b) {
    return b == 0? a: gcd(b, a % b);
}

int lcm(int x, int y) {
    return x * y / gcd(x, y);
}

int main() {
    // freopen("in.txt", "r", stdin);
    cin >> n >> m >> T;
    if (T - lcm(n, m) >= 0) cout <<"yes";
    else cout << "no";
    return 0;
}

G. Left and Right

题意: 给定一个数字n,给定一个长度为n-1的字符串,要求构造一个数字序列,使得这个数字序列遇到R时递增,遇到L时递减。

题解: 本题是构造题,当前打印的数字与后面的L和R的数目有关系。由于要求字典序最小,L为递减,那么就需要让L前面的R先增到一个最小值,然后再用L去递减。所以,每次遇到R时,就去计算后面有几个L,如果后面有k个L,那么从当前可以使用的第k+1大的数字开始递减打印。

代码:

#include <bits/stdc++.h>

using namespace std;

int const N = 2e5 + 10;
typedef long long LL;
typedef pair<int, int> PII;

int n, m, T;

int main() {
    // freopen("in.txt", "r", stdin);
    cin >> n;
    getchar();
    int maxv = 1, minv = 1;
    for (int i = 1; i < n; ++i) {
        char op = getchar();
        if (op == 'R') {
            for (int j = maxv; j >= minv; --j) cout << j << endl;
            maxv ++;
            minv = maxv;
        }
        else maxv ++;
    }
    for (int i = maxv; i >= minv; --i) cout << i << endl;
    return 0;
}

K. Run-Length Encoding, Run!

题意: 签到

题解: 签到

代码:

#include <bits/stdc++.h>

using namespace std;

int const N = 2e5 + 10;
typedef long long LL;
typedef pair<int, int> PII;

int n, m, T;

int main() {
    // freopen("in.txt", "r", stdin);
    string op, s;
    cin >> op >> s;
    if (op == "E") {
        for (int j = 0, i = 0; i < s.size(); ) {
            while(j < s.size() && s[i] == s[j]) j++;
            cout << s[i] << j - i;
            i = j;
        }
    }
    else {
        for (int i = 0; i < s.size(); ++i) {
            if (!isdigit(s[i])) {
                for (int j = 0; j < s[i + 1] - '0'; ++j) cout << s[i];
                i++;
            }
        }
    }
    return 0;
}

// H3e2l3o1W1o3r4l2d1!2
// H3e2l3o1W1o3r4l2d1!2
// HHHeellloWooorrrrlld!!
// HHHeellloWooorrrrlld!!

L. Superdoku

题意: 给定n和m,给定m行,要求构造出其余n-m行,使得每行、每列都是1~n的全排列。 1 < = n < = 100 , 0 < = m < = n 1<=n<=100, 0<=m<=n 1<=n<=100,0<=m<=n

题解: 前m行给定,那么就是已知了一些约束关系,使用 h [ x ] [ i ] h[x][i] h[x][i]表示x曾经出现在第i行, l [ x ] [ i ] l[x][i] l[x][i]表示x曾经出现在第j列。那么对于第k行,就是在做二分图匹配,左部图为数字 1 ∼ n 1\sim n 1n,右部图为列 1 ∼ n 1\sim n 1n。如果当前数字x曾经出现在第t列,即 l [ x ] [ t ] = 1 l[x][t]=1 l[x][t]=1,那么左部图的x到右部图的t就没有连边。如果在做二分图匹配的过程中没有找到匹配,那么无解。

代码:

#include <bits/stdc++.h>

using namespace std;

int const N = 100 + 10;
typedef long long LL;
typedef pair<int, int> PII;

int n, m, T;
int g[N][N], h[N][N], l[N][N];
int match[N], st[N];

bool find(int x) {
    for (int i = 1; i <= n; ++i) {
        if (l[x][i]) continue;
        if (!st[i]) {
            st[i] = 1;
            if (!match[i] || find(match[i])) {
                match[i] = x;
                return true;
            }
        }
    }
    return false;
}

int main() {
    cin >> n >> m;
    int flg = 1;
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            cin >> g[i][j];
            if (h[g[i][j]][i] || l[g[i][j]][j]) flg = 0;
            h[g[i][j]][i] = 1, l[g[i][j]][j] = 1;
        }
    }
    if (!flg) {
        cout << "no\n";
        return 0;
    }
    for (int i = m + 1; i <= n; ++i) {
        memset(match, 0, sizeof match);
        for (int j = 1; j <= n; ++j) {
            memset(st, 0, sizeof st);
            if (!find(j)) flg = 0;
        }
        for (int j = 1; j <= n; ++j) {
            g[i][j] = match[j];
            h[g[i][j]][i] = 1, l[g[i][j]][j] = 1;
        }
    }

    if (!flg ) {
        cout << "no\n";
        return 0;
    }
    cout << "yes\n";
    for (int i =1 ; i <=n ;++i) {
        for (int j = 1; j <= n; ++j) 
            cout << g[i][j] << " ";
        cout << endl; 
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值