Codeforces Round 984 (Div. 3)(A-F)

https://codeforces.com/contest/2036

A:

思路:额,大家都会,没什么思路,直接见代码。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define mp make_pair
#define endl '\n'
#define fo(i,l,r) for(int i=(l);i<=(r);++i)

void solve()
{
    int n, m, k;
    cin >> n;
    vi a(n+1);
    int flag = 0;
    fo(i,1,n){
        cin >> a[i];
    }
    for (int i=2; i<=n; i++){
        int ma = max(a[i-1], a[i]);
        int mi = min(a[i-1], a[i]);
        
        if (!(ma - mi==5 || ma-mi==7)){
            flag = 1;
            break;
        }
    }
    if (flag){
        cout << "NO" << endl;
    }
    else{
        cout << "YES" << endl;
    }
}

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

B:

思路:拿map存一下,再放在数组里排个序,取前n个加起来就行。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define pb push_back
#define endl '\n'
void solve()
{
    int n, m, k;
    cin >> n >> k;
    map<int, int> mp;
    for (int i = 1; i<=k; i++){
        int x, y;
        cin >> x >> y;
        mp[x]+=y;
    }
    priority_queue<int> q;
    for (auto [x, y] : mp){
        q.push(y);
    }
    int sum = 0, cnt=0;
    while (q.size() && cnt <n){
        int y = q.top();
        q.pop();
        sum += y;
        cnt++;
    }
    cout << sum << endl;
}

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

C:

思路:先找一遍初始时得“1100”,再对替换得求替换前和替换后的值,做差加上初始值即可,想一下为什么判断时只要或一下就行,因为它最多只能满足一次,可以自己推一下。

#include <bits/stdc++.h>
using namespace std;
#define vi vector<int>
#define vvi vector<vi>
#define endl '\n'
void solve()
{
    int n, m, q;
    string s;
    cin >> s;
    cin >> q;
    int num = 0;
    auto check = [&](int x)->bool
    {
        if (x < 0 || x + 3 >= s.size()) return false;
        if (s[x]=='1'&&s[x+1]=='1'&&s[x+2]=='0'&&s[x+3]=='0') return true;
        return false;
    };
    for (int i = 0; i + 3 < s.size(); i++) {
        if (check(i)) {
            num++;
        }
    }
    while (q--) {
        int i;
        char v; 
        cin >> i >> v;
        i--;
        if (v != s[i]){
            bool before = check(i-3)||check(i-2)||check(i-1)||check(i);
            s[i] = v;
            bool after = check(i-3)||check(i-2)||check(i-1)||check(i);
            num += (after-before);
        }
        cout << (num>0? "YES" : "NO") << endl;
    }
}

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

D:

从外层向内层求,一层做一个数组记录然后遍历求“1543”的个数,注意最后的判断取%个数就比较好弄,这题还是比较典的。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define endl '\n'
void solve()
{
    int n, m, k;
    cin >> n >> m;
    vector<string> s(n);
    for (int i = 0; i<n; i++){
        cin >> s[i];
    }
    vi arr(n*m);
    int count = 0;
    for (int i = 0; (i+1)*2<=n && (i+1)*2<=m; i++){
        int pos = 0;
        for (int j = i; j<m-i; j++) arr[pos++] = s[i][j];
        for (int j = i+1; j<n-i-1; j++) arr[pos++] = s[j][m-i-1];
        for (int j = m-i-1; j>=i; j--) arr[pos++] = s[n-i-1][j];
        for (int j = n-i-2; j>i; j--) arr[pos++] = s[j][i];

        for (int k = 0; k<pos; k++) {
            if (arr[k]=='1'&&arr[(k+1)%pos]=='5'&&arr[(k+2)%pos]=='4'&&arr[(k+3)%pos]=='3') count++;
        } 
    }
    cout << count << endl;
}

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

E:

思路:有题可知,或运算后的下一层大于大于上一层,预先处理出数组,再根据要求进行二分,这是一道很好的二分题,需要对二分有清楚认识,正确区分左右边界,看代码很容易懂。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define vvi vector<vi>
#define endl '\n'
#define fo(i,l,r) for(int i=(l);i<=(r);++i)
void solve()
{
	int n, m, k, q;
	cin >> n >> k >> q;
	vvi a(n+1, vi(k+1));
	fo(i,1,n){
		fo(j,1,k){
			cin >> a[i][j];
			a[i][j]|=a[i-1][j];
		}
	}
	while (q--){
		cin >> m;
		int l_pos = 1, r_pos=n;
		while (m--){
			int i, c;
			char o;
			cin >> i >> o >> c;
			if (o == '<'){
				int l = 0, r = n+1;
				while (l+1 < r){
					int mid = (l+r) >> 1;
					if (a[mid][i] < c) l = mid;
					else r = mid;
				}
				if (l < r_pos) r_pos = l;
			}
			else {
				int l = 0, r = n+1;
				while (l+1 < r){
					int mid = (l+r) >> 1;
					if (a[mid][i] > c) r = mid;
					else l = mid;
				}
				if (r > l_pos) l_pos = r;
			}
		}
		if (l_pos <= r_pos) cout << l_pos << endl;
		else cout << "-1" << endl;
	}
}

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

F:

一道很好的异或题,让我对异或的理解也是加深和丰富了,建议去做做。

思路:首先要知道一个数异或自己为0,和异或前缀,下面是异或前缀的快速求法:

int get(int n) {
    if (n % 4 == 0) {
        return 0;
    } else if (n % 4 == 1) {
        return n - 1;
    } else if (n % 4 == 2) {
        return 1;
    } else {
        return n;
    }
}
void solve() {
    cin >> r; // 求r的前缀异或
    r++;
    int ans = get(r);
}

可以自己推几个数就明白了。

因此对于l,r之间的数只要求出前缀,再把不用的去除掉,大概思路就是这样,接下看求区间l,r的异或,代码如下:

void solve()
{
    int l, r, i, k;
    cin >> l >> r >> i >> k;
    int ans = get(++r)^get(l);
}

分清有趣为模2^{i}不为k,无趣为模2^{i}k,因此算出区间l,r的异或再异或掉无趣的,对无趣的数进行分析,以k为5为例画图:

前面部分又是连续区间,我们只要改变进制右移求前缀(这里注意向上取整),再左移回来

r = (r-k+(1<<i)-1) >> i;
l = (l-k+(1<<i)-1) >> i;
ans ^= (get(r)^get(l)) << i;

再考虑后半部分的个数,为偶数异或为0,为奇数异或还剩个k,最后异或一下。

全部代码如下:

#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
    int l, r, i, k;
    cin >> l >> r >> i >> k;
    auto get=[&](int n)->int
    {
        if (n % 4 == 0) return 0;
        else if (n % 4 == 1) return n-1;
        else if (n % 4 == 2) return 1;
        else return n;
    };
    int ans = get(++r)^get(l);
    r = (r-k+(1<<i)-1) >> i;
    l = (l-k+(1<<i)-1) >> i;
    ans ^= (get(r)^get(l)) << i;
    if ((r ^ l) & 1){ //判断奇偶
        ans ^= k;
    }
    cout << ans << endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    
    return 0;
}

小结:这场Div3还是考的是简单的知识的深度运用,比如二分,异或,但又不是简单,需要有深刻的认识,这场打昏了,希望下次能多开几道。

(算竞萌新,有误请指正)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wirepuller_king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值