Atcoder Beginner Contest 406

比赛链接:ABC406

A - Not Acceptable

将小时转换成分钟直接进行判断。

时间复杂度: O ( 1 ) O(1) O(1)

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    if (a * 60 + b >= c * 60 + d) cout << "Yes" << endl;
    else cout << "No" << endl;
    return 0;
}

B - Product Calculator

根据题意进行模拟,为了避免 overflow 可以使用 __int128_t 来储存计算器当前展示的值。

时间复杂度: O ( N + K ) O(N + K) O(N+K)

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 105;
int n, k, a[N];

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> k;
    for (int i = 1; i <= n; i++) cin >> a[i];
    __int128_t now = 1;
    int inf = 0;
    for (int i = 1; i <= k; i++) inf = inf * 10 + 9;
    for (int i = 1; i <= n; i++) {
        if (now > inf / a[i]) now = 1;
        else now *= a[i];
    }
    string ans;
    while (now) ans.push_back('0' + now % 10), now /= 10;
    for (int i = ans.size() - 1; i >= 0; i--) cout << ans[i];
    cout << endl;
    return 0;
}

C - ~

  • 根据题目条件可知,要找的波浪形的子数组,一定先增大在减小最后再增大。
  • 我们只需要找到一个连续递减部分,再在这个连续递减的部分两侧加上至少一个数就能构造出满足题目条件的子数组。
  • 每一个连续递减部分能构成的满足题目条件的子数组的数量为这个部分 前面连续递增的长度 × \times × 后面连续递增的长度。
  • 因此,只需要找到原数组每个连续递增部分的长度,答案即为所有两个相邻的连续递增部分的长度的乘积的和。

时间复杂度: O ( N ) O(N) O(N)

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 3e5 + 5;
int n, p[N], cnt[N];

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n;
	for (int i = 1; i <= n; i++) cin >> p[i];
	int num = 1;
    for (int i = 2; i <= n; i++) {
		if (p[i] > p[i - 1]) cnt[num]++;
		else if (cnt[num]) num++;
	}
	ll ans = 0;
	for (int i = 1; i <= num; i++) ans += 1LL * cnt[i - 1] * cnt[i];
	cout << ans << endl;
    return 0;
}

D - Garbage Removal

对于每一个行、列分别用一个 set 维护这一行中的点的纵、横坐标,每次查询完将对应的点的坐标从 set 中删除。

时间复杂度: O ( ∑ i = 1 Q T log ⁡ N + N log ⁡ N ) O(\sum_{i = 1}^Q T\log N + N\log N) O(i=1QTlogN+NlogN),其中 T T T 是每次需要删除的点的数量,并且 ∑ i = 1 Q T log ⁡ N ≤ N log ⁡ N \sum_{i = 1}^Q T\log N \le N\log N i=1QTlogNNlogN

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int h, w, n, q;
set<int> row[N], col[N];

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> h >> w >> n;
    for (int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        row[x].insert(y), col[y].insert(x);
    }
    cin >> q;
    while (q--) {
        int op, idx;
        cin >> op >> idx;
        if (op == 1) {
            cout << row[idx].size() << "\n";
            for (int i : row[idx]) col[i].erase(idx);
            row[idx].clear();
        }
        if (op == 2) {
            cout << col[idx].size() << "\n";
            for (int i : col[idx]) row[i].erase(idx);
            col[idx].clear();
        }
    }
    return 0;
}

E - Popcount Sum 3

从高位往低位考虑,总共放置 k k k 1 1 1,利用 d f s dfs dfs 找出答案,具体实现看代码。

时间复杂度: O ( ∑ i = 1 T i log ⁡ N ) O(\sum_{i = 1}^Ti\log N) O(i=1TilogN)

从高位往地位进行搜索,

  • 如果每一位都放 1 1 1,最多进行 log ⁡ N \log N logN s u m sum sum 就会大于 N N N
  • 如果前面都不放 1 1 1,最多进行 log ⁡ N − K \log N - K logNK 次就会被剪枝。
#include <bits/stdc++.h>
using namespace std;

#define int long long

const int mod = 998244353;
int n, k, c[65][65];

// 预处理组合数
void init() {
    c[0][0] = 1;
    for (int i = 1; i <= 60; i++) {
        c[i][0] = c[i][i] = 1;
        for (int j = 1; j < i; j++)
            c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
    }
}

// cur 是当前位置,sum 是当前的和,cnt 是剩余要放置的 1 的数量
int dfs(int cur, int sum, int cnt) {	
	// 不合法条件:sum 大于 n,剩余位置无法放下需要放置的 1
    if (sum > n || cnt > cur + 1) return 0;
    
    // 所有 1 都放完了,sum 就是要加上的答案
    if (cnt == 0) return sum % mod;
    // 剩余的 cnt 个 1 可以放在 0 - p 任意一个位置
    if (sum + (1LL << (cur + 1)) - 1 <= n) {
        int oup = ((1LL << (cur + 1)) - 1) % mod * c[cur][cnt - 1] % mod;
        oup = (oup + c[cur + 1][cnt] * (sum % mod) % mod) % mod;
        return oup;
    }
    return (dfs(cur - 1, sum, cnt) + dfs(cur - 1, sum + (1LL << cur), cnt - 1)) % mod;
}

void solve() {
    cin >> n >> k;
    cout << dfs(59, 0, k) << "\n";
}

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    init();
    int T;
    cin >> T;
    while (T--) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值