2022年湖南工学院ACM集训第五次周测AD题题解

Problem A Newbie

来源:第46届ICPC-ECFinal(东亚赛区总决赛) I 题 Future Coder

考察:思维,分类讨论

难度:橙题

本题大致思路是先将数组排序,排序后进行分类讨论。

  1. 若当前 a 选的数为负数,那么我们另一个数 b 只有 3 种选择的可能,分别是负数,0,正数,当 b 为负数时,可以发现乘法中负负得正,因此 a * b 恒大于 a + b,不符合条件;当 b 为 0 时,a * 0 永远为 0,而 a + 0 永远为负数,因此 a * b 恒大于 a + b,也不符合条件;当 b 为正数时,a * b 永远是负数,并且相乘后只会比原来的 a 更小,而 a + b 由于 b 是正数,因此 相加后只会比原来的 a 更大。因此 a * b < a + b。也就是说,当 a 选择负数时,方案种类即为正数的个数。
  2. 若当前 a 选的数为 0,同样 b 也有 3 种可能,分别是负数,0,正数。而刚才我们已经讨论了 0 和 负数 的情况,因此只分析其他两种。当 b 为 0 时,a * b = 0,a + b = 0,因此 a * b == a + b,不符合条件;当 b 为正数时,a * b = 0 ,a + b > 0,因此 a * b < a + b 符合条件。因此当 a 为 0 时,方案种数即为正数的个数。
  3. 若当前 a 选的数为 正数,同样 b 也有 3 种可能,分别是负数,0,正数。而刚才我们已经讨论了 负数 和 正数 以及 0 和 正数 的情况,因此只分析剩下的一种。当 b 为正数时,可以列出一下证明。

        当 a,b\in \mathbb{N^+} 时,a,b 分别为何值时,满足不等式 a + b > a * b

=> a + b > a*b

=> 0 > a * b - (a + b) 将 a + b 移相。

=> 1 > a*b-(a+b)+1 做差配上 1

=> 1>(a-1)*(b-1) 合并式子

因此通过式子可以发现,当 a 为 1 时式子满足 当 b 为 1 时式子满足 当 a 和 b 均为 1 时式子满足,换句话说,只要 a 或 b 其中任意一个为 1 ,即可满足式子。

因此,当 a 选正数时,我们可以让 a 选 1,若a = 1,则 b 可以为任何正数,因此方案数为剩余正数个数,若 a 不为 1,那么我们应该让 b 为 1。这样就可以求出所有方案了。

这个题实际上可以不用推公式,自己多造几组数据,就可以发现这个原则。 

发现大家其实都发现了这个规律,但就是算不明白....

ps:赛时发现大家常犯的错误:不开long long,样例没过就直接交送罚时。完全没想到这题 dirt 率如此之高,希望大家以后还是多注意注意细节,尽可能自己捏一些数据验证一下。

#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
const ll mod = 1e9 + 7;
using namespace std;
ll a[2020200];
int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        sort(a + 1, a + 1 + n);
        ll sum = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i] <= 0) {
                int pos = lower_bound(a + 1 + i, a + 1 + n, 1) - a; //找到 1 所在的位置,也就是正数所在的第一个位置
                if (pos == n && a[pos] <= 0) { // 若没有正数,那么此轮无方案
                    continue;
                }
                else {
                    sum += n - pos + 1; // 否则加上正数区间个数
                }
            }
            else if (a[i] == 1) {
                sum += n - i; //如果当前为 1,那么除了该位置以外的后面所有的位置都可以被当成 b
            }
        }
        cout << sum << endl;
    }
    return 0;
}

Problem D 量角器

来源:AcWing 第 61 场周赛 B 题 指针

考察:dfs

难度:橙题

本题可以发现数据范围不超过 15,那么对于这种选数的题,我们可以直接dfs暴力求解即可。不难发现每次拨动我们可以任意选择顺时针或者逆时针,因此直接记录一下顺时针逆时针分别一共转了多少度,当n次拨动完后,判断一下是否相等即可,但是!!!!还有一点要注意,因为量角器是360度的,因此当你转动大于360后,实际上是不存在这种度数的,因此需要判断一下总转动度数对360取余后是否相等即可。

另外这题与上周的C题是极其相似的,除了相等情况的判定,其他几乎一模一样。还是希望大家赛后认认真真补题吧,不懂的可以问。

ps:由于数据有点水,赛时让两位同学代码水过去了,错误原因也正是大于360的情况。

#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
const ll mod = 998244353;
using namespace std;
int a[200];
int vis[200];
int n;
int f = 0;
void dfs(int x, int y, int now) { //x记录顺时针,y记录逆时针
    if (now == n + 1) {
        if (x % 360 == y % 360) {
            f = 1;
        }
        return;
    }
    dfs(x + a[now], y, now + 1);
    dfs(x, y + a[now], now + 1);
}
int main() {
    cin >> n;
    ll sum = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        sum += a[i];
    }
    dfs(0, 0, 1);
    if (f) {
        cout << "YES";
    }
    else {
        cout << "NO";
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值