[Codeforces Round #644 (div3)]1360


1360A - Minimal Square[思维]
1360B - Honest Coach[思维]
1360C -Similar Pairs[思维]
1360D - Buying Shovels[思维]
1360E - Polygon[思维]
1360F - Spy-string[暴力]
1360G - A/B Matrix[构造]
1360H - Binary Median[思维]



这场都是思维题,题目就不贴过来了
感觉需要做点模拟题的样子。。
想倒是能想到,实现起来老是有bug



目录

1360A - Minimal Square[思维]

题意

求要在一个正方形内构造两个长方形,长和宽分别为 a , b a, b a,b
问这个正方形面积最小为多少

做法

显然如果将两个叠起来放,必然选择较小的那条边作为叠起来的宽度
但这个时候还要比较另一条边的大小,选取最大的值
也就是说 m a x ( 2 ∗ b , a ) max(2*b, a) max(2b,a) 即其中一种方式构成的最小正方形的边长, m a x ( 2 ∗ a , b ) max(2*a, b) max(2a,b) 就是另一种
两者取 m i n min min 即可

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(a,b)    ((a)>(b)?(b):(a))
#define max(a,b)    ((a)>(b)?(a):(b))
const int maxn = 50 + 5;

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int a, b;
        scanf("%d%d", &a, &b);
        a = min(max(a, 2 * b), max(2 * a, b));
        printf("%d\n", a * a);
    }
    return 0;
}


目录

1360B - Honest Coach[思维]

题意

要构造 A , B A,B A,B 两个集合
使 a b s ( m a x ( A ) − m i n ( B ) ) → m i n abs(max(A) - min(B)) \rightarrow min abs(max(A)min(B))min

做法

由于没有要求集合元素个数, A , B A, B A,B 两个集合我们可以自由选择
那么只要选取 两个差值绝对值最小的数 就好了
把这两个差值绝对值最小的两个数 的较大一个数放到集合 A A A,较小的一个放到集合 B B B
然后其他的数也可以不用管了,或者说比扔到 A A A 这个集合的数小的可以扔到集合 A A A
同理比扔到 B B B 这个集合的数大的可以扔到集合 B B B

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(a,b)    ((a)>(b)?(b):(a))
#define max(a,b)    ((a)>(b)?(a):(b))
const int inf = 0x3f3f3f3f;
const int maxn = 50 + 5;

int a[maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)	scanf("%d", &a[i]);
        sort(a + 1, a + 1 + n);
        int ans = inf;
        for(int i = 2; i <= n; ++i)
            ans = min(ans, a[i] - a[i - 1]);
        printf("%d\n", ans);
    }
    return 0;
}



目录

1360C -Similar Pairs[思维]

题意

如果两个数 x x x y y y 具有相同的奇偶性(除以 2 2 2 时的余数相同),
或者如果 x − y = 1 x-y=1 xy=1 ,我们称它们为相似的数 x x x y y y
问这个长度为 n n n 的数组能否完全构造成相似数
保证 n n n 是偶数

做法

首先当 奇数的个数 为 偶数时,肯定可以
剩下的情况就是多了一个奇数,那么对应的也会多出一个偶数
只要排序遍历一遍数组,查找是否有两个相邻的数就可以了
因为相邻的数必然是一个奇数一个偶数,正好符合多出来的两个数

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(a,b)    ((a)>(b)?(b):(a))
#define max(a,b)    ((a)>(b)?(a):(b))
const int inf = 0x3f3f3f3f;
const int maxn = 50 + 5;

int a[maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, c = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            if(a[i] % 2)    c += 1;
        }
        if(c % 2 == 0) {
            puts("YES");
        }else{
            bool flag = false;
            sort(a + 1, a + 1 + n);
            for(int i = 2; i <= n; ++i) {
                if(a[i] - a[i - 1] == 1) {
                    flag = true;
                    break;
                }
            }
            printf("%s\n", flag ? "YES" : "NO");
        }
    }
    return 0;
}



目录

1360D - Buying Shovels[思维]

题意

Polycarp 想买 n n n 把铲子,商店卖的铲子有 k k k 种包装,第 i i i 种包装由 i i i 把铲子组成
他买的时候只能选择一种包装
问最少需要买多少包

做法

显然我们要选择的是 n n n 的因子中,小于等于 k k k 的最大因子
开根号从大的开始遍历,第一个符合条件的就是

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(a,b)    ((a)>(b)?(b):(a))
#define max(a,b)    ((a)>(b)?(a):(b))
const int inf = 0x3f3f3f3f;
const int maxn = 50 + 5;

int a[maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, k;
        scanf("%d%d", &n, &k);
        if(k >= n) {
            puts("1");
        }else{
            int x = sqrt(n * 1.0), ans = n;
            for(int i = x; i > 0; --i) {
                if(n % i == 0) {
                    if(i <= k)      ans = min(ans, n / i);
                    if(n / i <= k)  ans = min(ans, i);
                }
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}



目录

1360E - Polygon[思维]

题意

左边和右边都有炮台可以放炮,上面的炮台向下放炮,左边的炮台向右放炮
每次放的炮都会到最边界或者有 1 1 1 的地方前
给出最终的图, 1 1 1 是炮停到的地方
问是否能得到这个图

做法

如果不是在右边界或者下边界的话
只要判断为 1 1 1 的该位置的 右边 或者 下边 是否存在 1 1 1 即可

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50 + 5;

char s[maxn][maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n; bool flag = true;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%s", s[i] + 1);
            s[n + 1][i] = s[i][n + 1] = 0;
        } 
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) {
                if(i == n || j == n)    continue;
                if(s[i][j] == '1' && s[i + 1][j] != '1' && s[i][j + 1] != '1') {
                    flag = false;
                    break;
                }
            }
        }
        printf("%s\n", flag ? "YES" : "NO");
    }
    return 0;
}



目录

1360F - Spy-string[暴力]

题意

问是否存在一个串,使得该串与给定的 n n n 个串不同的地方只有一个

做法

n , m ≤ 10 n, m \leq 10 n,m10,范围很小
因此可以给定最后结果串先与 s [ 0 ] s[0] s[0] 相同
然后暴力遍历结果串的每一个位置
暴力遍历每个位置更改成 26 26 26 个字母的其中一个
判断更改后是否可以满足条件
时间复杂度为 O ( 26 ∗ 10 ∗ 10 ∗ 10 ∗ T ) O(26*10*10*10*T) O(26101010T)

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10 + 5;

char s[maxn][maxn];
char res[maxn];
int n, m;

bool check() {
    for(int i = 0; i < n; ++i) {
        int cnt = 0;
        for(int j = 0; j < m; ++j)
            cnt += (res[j] == s[i][j] ? 0 : 1);
        if(cnt > 1) return false;
    } 
    return true;
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        bool flag = false;
        scanf("%d%d", &n, &m); 
        res[m] = 0;
        for(int i = 0; i < n; ++i)  scanf("%s", s[i]);
        for(int i = 0; i < m; ++i)  res[i] = s[0][i];
        for(int i = 0; i < m; ++i) {
            for(int j = 'a'; j <= 'z'; ++j) {
                res[i] = j;
                if(check()) {
                    flag = true;
                    break;
                }
            }
            if(flag)    break;
            res[i] = s[0][i];
        }
        printf("%s\n", flag ? res : "-1");
    }
    return 0;
}



目录

1360G - A/B Matrix[构造]

题意

有一个长 n n n m m m 的矩形,要使得每行有 a a a 1 1 1,每列有 b b b 1 1 1
是否存在这样的图

做法

首先是去除不可能的情况
在行填充时,必然会对列产生一定的影响;同理列填充的时候也会对行产生影响
观察样例可以发现,其实是跟比例有关
m / a = = n / b m / a == n / b m/a==n/b 的时候,是会存在解的
当然这个公式中 a , b a, b a,b 都不能为 0 0 0
可以移项一下,变成 m ∗ b = = n ∗ a m * b == n * a mb==na,这样就可以处理 a , b a, b a,b 0 0 0 的情况了
a , b a, b a,b 中只有一个为 0 0 0 显然是不可能存在的情况

接下来处理填充
尝试自己构造第四个样例 4 4 4 4 4 4 2 2 2 2 2 2,可以得到下图
可以发现其实只要连续填充行所需要的个数 a a a,然后每次偏移一定的偏移量,就可以得到最后的图
在这里插入图片描述
问题是偏移量的计算

偏移是为了使列满足需要的个数 b b b,也就是为了使得每一列都可以填充到
又每次偏移的时候,行都会向下移动一行
也就是 偏移量 ∗ * % m = = 0 \% m == 0 %m==0
n n n 次偏移后正好 m m m 列每列遍历到的次数都是一样的

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50 + 5;

int res[maxn][maxn];

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, m, a, b;
        // puts("");
        scanf("%d%d%d%d", &n, &m, &a, &b);
        if(m * b != n * a)  puts("NO");
        else{
            puts("YES");
            int k;
            memset(res, 0, sizeof(res));
            for(k = 1; k < m; ++k)
                if(k * n % m == 0)
                    break;
            // printf("%d\n", k);
            for(int i = 0, x = 0; i < n; ++i, x += k) {
                for(int j = 0; j < a; ++j) {
                    res[i][(j + x) % m] = 1;
                }
            }
            for(int i = 0; i < n; ++i) {
                for(int j = 0; j < m; ++j)
                    printf("%d", res[i][j]);
                puts("");
            }
        }
    }
    return 0;
}



目录

1360H - Binary Median[思维]

题意

长度为 n n n,全为 0 , 1 0, 1 0,1 的字符串
现在拿走 m m m 个串后
问大小处在最中间(即中位数)的串是哪个串
如果是在两个数中间,则取较小的一个数

做法

首先将这些串都转化为十进制的数
由于 m m m 最大为 100 100 100
只需要将原本的中位数分别往左右的 100 100 100 个数,或者更多存入动态数组中
每次删除对应位置的数
最后的得到的数组中,数组的中位数也就是要求的中位数
最后输出的时候再转为二进制

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 60 + 5;

char s[maxn];
vector<ll> v;

ll getT(int m) {
    ll x = 0, y = 1ll;
    for(int i = m - 1; i >= 0; --i, y <<= 1ll)
        x += (s[i] == '0' ? 0 : y);
    return x;
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n, m; v.clear();
        scanf("%lld%d", &n, &m);
        ll k = (1ll << (m - 1));  // 中位数
        for(int i = -110; i < 110; ++i)
            v.push_back(k + i);
        ll x;
        for(int i = 0; i < n; ++i) {
            scanf("%s", s); x = getT(m);
            if(x < v[0])
                v.erase(v.begin());
            else if(x > v.back())
                v.erase(v.end() - 1);
            else
                v.erase(find(v.begin(), v.end(), x));
        }
        x = v[(v.size() - 1) / 2];
        for(int i = m - 1; i >= 0; --i, x >>= 1ll)
            s[i] = x % 2 + '0';
        printf("%s\n", s);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值