AtCoder Beginner Contest 377 A-E题解

TOYOTA SYSTEMS Programming Contest 2024(AtCoder Beginner Contest 377) - AtCoder

A - Rearranging ABC

题目及数据范围:

思路:

判断abc字符出现的个数就可以

代码:

#include <bits/stdc++.h>
typedef long long ll;
const ll N=10000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll p1 , p2 , p3;


void solve(){
    std::string s;
    std::cin >> s;
    for (ll i = 0; i <= 2; i++) {
        if (s[i] == 'A') p1++;
        else if (s[i] == 'B') p2++;
        else p3++;
    }
    if(p1 == 1 && p2 == 1 && p3 == 1) std::cout << "Yes" << '\n';
    else std::cout << "No" << '\n';
}

signed main(){
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

B - Avoid Rook Attack

题目和数据范围:

思路:

模拟,开两个bool数组,记录每行每列有没有被标记,依题意就可以解决

代码:

#include <bits/stdc++.h>
typedef long long ll;
const ll N=10000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
std::string ss[10];
bool hang[8];
bool lie[8];

void solve(){
    for (ll i = 0; i <= 7; i++) std::cin >> ss[i];
    for (ll i = 0; i <= 7; i++)
        for (ll j = 0; j <= 7; j++)
            if(ss[i][j] == '#') {
                hang[i] = true;
                lie[j] = true;
            }
    ll ans = 0; 
    for (ll i = 0; i <= 7; i++)
        for (ll j = 0; j <= 7; j++)
            if(hang[i] == false && lie[j] == false) {
                ans++;
            }
    std::cout << ans << '\n';
}

signed main(){
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

C - Avoid Knight Attack

思路:

注意到n很大,直接开二维数组行不通。我们可以考虑记录哪些点不能走最后用总答案减去就行。关键在于怎么判断重复的点。我们可以利用map记录某个点有没有被标记过 ,键存进一个二维的对。这样就可以解决问题。

代码:

#include <bits/stdc++.h>
typedef long long ll;
const ll N=10000005;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll n , m;
std::map <std::pair<ll,ll> , bool> mapp;
ll dx[8] = {-2 , -1 , 1 , 2 , 2 , 1 , -1 , -2};
ll dy[8] = {1 , 2 , 2 , 1 , -1 , -2 , -2 , -1};

void solve(){
    std::cin >> n >> m;
    ll ans = 0;
    for (ll i = 1; i <= m; i++){
        ll x , y;
        std::cin >> x >> y;
        std::pair <ll , ll> ppp = std::make_pair(x , y);
        if(mapp[ppp] == false) ans++;
        mapp[ppp] = true;
        for (ll j = 0; j <= 7; j++){
            ll nx = dx[j] + x;
            ll ny = dy[j] + y;
            if (nx <= n && nx >= 1 && ny >=1 && ny <=n){
                std::pair <ll , ll> pp = std::make_pair(nx , ny);
                if(mapp[pp] == false) ans++;
                mapp[pp] = true;
            }
        }
    }
    std::cout << n * n - ans << '\n';
}

signed main(){
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

D - Many Segments 2

题目和数据范围:

思路:

枚举小于m的每个r,找有多少个可以l符合条件。设最小的符合条件的l的下表为a,那我们只要找到每个r对应的a,再求和就是答案。那怎么找对应的a呢?

首先如果只有一个区间,右端点可以选的l就是在l+1 - r这个范围内。

先把每个区间右端点能允许的最小l标记,再从小到大枚举r,如果前面的l比当前l还大,就只能顺着前面的l才能保证合法(依题意)因为从小到大,l也不会超过r。不用特判。

假设我们已经知道a_{r-1} ,如果当前i 没有使得R_{i} =i,那么就没有新的约束条件,就让他等于上一个推出来的a。如果存在,我们就有 a_{r}=max\left ( a_{r-1} ,l_{max}+1\right )i​ 。

代码:

#include <bits/stdc++.h>
typedef long long ll;
const ll N=1000005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n , m;
ll f[N];

void solve(){
    std::cin >> n >> m;
	for (ll i = 0; i <= m; i++) f[i] = 1;
	for (ll i = 0; i < n; i++){
		ll a , b;
		std::cin >> a >> b;
		f[b] = std::max(f[b] , a + 1);
	}
	for (ll i = 1; i <= m; i++)
		f[i] = std::max(f[i] , 	f[i-1]);
	ll ans = 0;
	for (ll i = 1; i <= m; i++)
		ans += i - f[i] + 1;
	std::cout << ans << '\n';
}

signed main(){
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ll t = 1; //std::cin >> t;
    while (t--) solve();
    return 0;
}

E - Permute K times 2

题目和数据范围:

思路:

把他当图论做,会发现就是一个有n个环的图。每个点每回合会移动。我们只要算每个环长度,算算会走到哪里,就可以算出答案。难点就在于能不能看出来这个。

这个自己写的太丑观感不好,代码直接搬jly老师的了。

代码:

#include <bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;

int power(int a, i64 b, int p) {
    int res = 1;
    for (; b; b /= 2, a = 1LL * a * a % p) {
        if (b & 1) {
            res = 1LL * res * a % p;
        }
    }
    return res;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    i64 K;
    std::cin >> N >> K;
    
    std::vector<int> P(N);
    for (int i = 0; i < N; i++) {
        std::cin >> P[i];
        P[i]--;
    }
    
    std::vector<bool> vis(N);
    for (int i = 0; i < N; i++) {
        if (vis[i]) {
            continue;
        }
        
        int j = i;
        std::vector<int> a;
        while (!vis[j]) {
            vis[j] = true;
            a.push_back(j);
            j = P[j];
        }
        
        i64 d = power(2, K, a.size());
        for (int x = 0; x < a.size(); x++) {
            P[a[x]] = a[(x + d) % a.size()];
        }
    }
    for (int i = 0; i < N; i++) {
        std::cout << P[i] + 1 << " \n"[i == N - 1];
    }
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值