Codeforces Round #777 (Div. 2)

A Madoka and Math Dad

题意:给出一个数,用1~9的数字的总和等于这个数,并将需要拼的数字组成一个新的数,并要求相邻的数字不相同,如5只能拼出212(最大),4只能用121拼出(不能用211,11相邻了)
一开始以为暴搜,写完发现50都跑不出来,别说1000了,才想到我这是每一次遍历都要找9个值,时间复杂度太大了。
贪心!然后贪心思路发现,要想要数字最大,虽然让位数最高的数最大,但敌不过位数的比较,位数多了数自然就大了,位数想要越多,每一位的数就得越小,而且由于相邻的两数不能相同,则所有的数都用1和2拆出来,这样数就最大了。
有两个式子,x为2的个数,y为1的个数
2*x + y = n
x = y + 1或者x = y 或者x = y - 1(1和2的个数顶多查一个)

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int t;
    cin >> t;
    while(t -- )
    {
        int n; cin >> n;
        if(n == 1 || n == 2) {cout << n << endl; continue;}
        int one = 0, two = 0;
        if((n + 1) % 3 == 0) two = (n + 1) / 3, one = (n - 2) / 3;
        else if((n - 1) % 3 == 0) two = (n - 1) / 3, one = (n + 2) / 3;
        else two = n / 3, one = n / 3;

        while(one || two)
        {
            if(two >= one){
                if(two) two -- , cout << 2;
                if(one) one --, cout << 1;
            }
            else {
                if(one) one --, cout << 1;
                if(two) two -- , cout << 2;
            }
        }
        cout << endl;
    }
    return 0;
}

B Madoka and the Elegant Gift

题意:给出01二维矩阵,1为黑色,0为白色,其子矩阵的定义为子矩阵的值都是1,判断二维矩阵中的子矩阵是否有相交,若没有(可包含)则输出YES,否则输出NO。
重叠情况
解法:(麻烦解法)从第一个块开始遍历,如果为1,则从该点找行和列能”构成子矩阵”的行和列(不一定),再判断这个“子矩阵”中是否都是1,然后在判断这个子矩阵左和上是否有之前的子矩阵,如果相邻则肯定有相交的地方。

#include <bits/stdc++.h>

using namespace std;

const int N = 110;

bool g[N][N];
char a[N][N];

int main()
{
    int t; cin >> t;

    while(t -- )
    {
        int n, m; cin >> n >> m;
        memset(g, 0, sizeof g);
        memset(a, 0, sizeof a);

        for(int i = 1; i <= n; i ++ )
            for(int j = 1; j <= m; j ++ )
                cin >> a[i][j];

        int st = false;

        for(int i = 1; i <= n; i ++ ){
            for(int j = 1; j <= m; j ++ ){
                if(a[i][j] == '1' && !g[i][j]){
                    int row = i, col = j;
                    g[row][col] = true;
                    while(a[i][col + 1] == '1') g[i][col + 1] = true, col ++;
                    while(a[row + 1][j] == '1') g[row + 1][j] = true, row ++;

                    for(int x = i + 1; x <= row; x ++ ){
                        for(int y = j + 1; y <= col; y ++ ){
                            if(a[x][y] == '0') st = true;
                            g[x][y] = true;
                        }
                        if(st) break;
                    }

                   if(st) break;

                   for(int x = j; x <= col; x ++ )
                        if(g[i - 1][x]) {st = true; break;}
                   for(int y = i; y <= row; y ++ )
                        if(g[y][j - 1]) {st = true; break;}
                }
            }
            if(st) break;
        }

        if(st) cout << "NO" << endl;
        else cout << "YES" << endl;
    }

    return 0;
}

但起始不需要那么麻烦,全部遍历一遍,若为黑块,则判断以其为起点的2 ∗ * 2小矩阵是否都是1,若不是则输出NO,否则遍历完输出YES。
要遍历2 ∗ * 2的小矩阵的原因为最后形成的为子矩阵,四四方方的,如果两子矩阵有相交的地方则为一定唯有上述子矩阵不全为1的情况。
大佬的解释

#include"bits/stdc++.h"
#define all(x) x.begin(),x.end()
#define len(x) x.size()
#define INF (1e9)
#define vi vector<int>
#define ll long long
#define db double
#define vvi vector<vector<int>>
using namespace std;
 
void solve() {
    int n, m;
    cin >> n >> m;
    vvi a(n + 1, vi(m + 1));
    for (int i = 1; i <= n; i++) {
        string temp;
        cin >> temp;
        for (int j = 0; j < m; j++) {
            a[i][j + 1] = temp[j] - '0';
        }
    }
    
    for (int i = 1; i < n; i++) {
        for (int j = 1; j < m; j++) {
            int sum = a[i][j] + a[i][j + 1] + a[i + 1][j] + a[i + 1][j + 1];
            if (sum == 3) {
                cout << "NO" << endl;
                return;
            }
        }
    }
    cout << "YES" << endl;
}
 
int main() {
    int n;
    cin >> n;
    while(n--) {
        solve();
    }
    return 0;
}

C Madoka and Childish Pranks

题意,给出一个01二维矩阵,通过下面的图形尝试拼出所给的01矩阵,注意后图画的地方会覆盖先图画的地方。若不能拼出,则输出-1,若能拼出,输出需要操作的次数(不要求操作的次数最少,能凑出就行),后面再输出操作的左上角和右下角的坐标,即答案不唯一。
在这里插入图片描述
样例1
01000
10100
01010
00110
在这里插入图片描述
贪心,重点是要求题目操作的次数不要求最小值,所以可以一个黑块一个黑块的涂,通过第一个样例给我了灵感,可以通过01(可以横着也可以竖着)这样的小块去拼出这个01矩阵,即有多少个黑块就有多少个操作(输出-1的情况为第一行第一列的块为黑色,不能通过下图的两个拼出)。
还需要注意的是第一列黑色方块只能通过第一个进行拼出
在这里插入图片描述
想要拼出这种,如果按从小到大的顺序拼,后面黑色的会将前面黑色的方块覆盖,所以遍历的时候需要从后向前输出
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 110;

char a[N][N];
vector<pair<int, int> > v;

int main()
{
    int t; cin >> t;
    while(t -- )
    {
        int n, m; cin >> n >> m;
        v.clear();

        for(int i = 1; i <= n; i ++ )
            for(int j = 1; j <= m; j ++ )
                cin >> a[i][j];

        if(a[1][1] == '1') { cout << -1 << endl; continue; }

        int cnt = 0;
        for(int i = n; i >= 1; i -- )
            for(int j = m; j >= 1; j -- )//从后向前输出
                if(a[i][j] == '1') cnt ++, v.push_back({i, j});

        cout << cnt << endl;
        for(int i = 0; i < v.size(); i ++ )
        {
            pair<int, int> p = v[i];
            if(p.second == 1) {
                cout << p.first - 1 << ' ' << p.second << ' ' << p.first << " " << p.second << endl;
            }
            else cout << p.first << ' '<< p.second - 1 << ' ' << p.first << ' ' << p.second << endl;
        }
    }
    return 0;
}

D Madoka and the Best School in Russia
参照大佬讲解

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int x, d, k;

bool check(int n)
{
    if(n < 4) return 1;
    if(n % 2 == 0 || n % 3 == 0) return 0;
    for(int i = 5; i * i <= n; i += 6)
        if(n % i == 0 || n % (i + 2) == 0) return 0;
    return 1;
}

int main()
{
    int t; cin >> t;
    while(t -- )
    {
        k = 0;
        cin >> x >> d;
        while(x % d == 0) k ++, x /= d;
//        cout << k << endl;
        if(k < 2) cout << "NO" <<endl;
        else if(!check(x)) cout << "YES" <<endl;//s是合数
        else if(check(d))cout << "NO" << endl;//s不是合数,d是质数
        else printf(k > (x * x == d) + 2 ? "YES\n" : "NO\n");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值