AtCoder Beginner Contest 343

前面两道阅读理解直接跳过。

C - 343

大意

给定n,找到一个不超过n最大数x,要求x完全立方数且为回文数

思路

小于等于n的完全立方数只有n^{\frac{1}{3}}个,因此枚举判断即可。

判断回文数时可用to_string转成字符串再判断。

代码

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;


int main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	ll n, ans = 1;
	cin >> n;

    auto check = [&](ll x){
        string s, t;
        t = s = to_string(x);
        reverse(t.begin(), t.end());
        return s == t;
    };

	for(ll i = 1; i * i * i <= n; i++)
	    if(check(i * i * i)) ans = i * i * i;
	cout << ans << endl;
	return 0;
}

D - Diversity of Scores

大意

初始n个人都是0分。

i个时刻,第A_i个人分数增加 B_i 。

问每个时刻后,不同分数的个数。

思路

虽然分数的范围很大,但最多只有20万名选手,所以不同的分数最多只有20万个。

可以使用map维护每个分数出现的次数

代码

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
typedef long long ll;

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, t;
	cin >> n >> t;

    vector<ll> c(n + 1);
    unordered_map<ll, ll> mp;

	mp[0] = n;
	for(int i = 1; i <= t; i++){
		ll a, b;
		cin >> a >> b;
		mp[c[a]]--;
		if(mp[c[a]] == 0) mp.erase(c[a]);
		c[a] += b;
		mp[c[a]]++;
		cout << mp.size() << endl;
	}
	
	return 0;
}

E - 7x7x7

大意

一个三维空间里放置了三个棱长为7正方体

给定a,b,c,要求

  • 恰好属于一个方块的体积是a
  • 恰好属于两个方块的体积是b
  • 恰好属于三个方块的体积是c

输出任意一种可行的摆放方式,没有则输出\texttt{No}

思路

首先a+2b+3c \ne 1029无解

由于数不大,我们可以直接枚举。(7^9=40,353,607

每个正方体放置的坐标范围是[-7,7],再远的坐标和-7,7的放置效果一样。

下面考虑在确定摆放位置后,如何求a,b,c

首先c就是三个正方体的长、宽、高的交集之积。(与求线段和正方体的交集类似)

这里我们设f(a,b,c)为三条长度为7,起点分别为a,b,c的三条线段的交集(不包括两两之间的交集)

f(a,b,c)=\min(0,\min(x,y,z)+7-\max(x,y,z))

c=f(a1,a2,a3)*f(b1,b2,b3)*f(c1,c2,c3)

b就是两两相交,但是会重复计算c,需要减去重叠部分

f(a,b)为两条长度为7,起点分别为a,b的两条线段的交集。

f(a,b)=\min(\min(x,y)+7-\max(x,y),0)

b=f(a1,a2)*f(b1,b2)*f(c1,c2)+f(a1,a3)*f(b1,b3)*f(c1,c3)+f(a2,a3)*f(b2,b3)*f(c2,c3)-3c

不用计算a,因为通过b,c就能得到a

计算出b,c后,判断是否与要求的b,c相等,若相等,则为合法方案,直接输出即可。

代码

#include<iostream>
#include<cstring>
using namespace std;
int a, b, c;

int min(int x, int y, int z){
    return min(x, min(y, z));
}

int max(int x, int y, int z){
    return max(x, max(y, z));
}

int f(int x, int y, int z){
    if(min(x, y, z) + 7 - max(x, y, z) < 1) return 0;
    return min(x, y, z) + 7 - max(x, y, z);
}

int f(int x, int y){
    if(min(x, y) + 7 - max(x, y) < 1) return 0;
    return min(x, y) + 7 - max(x, y);
}

int V3(int a1, int b1, int c1, int a2, int b2, int c2, int a3, int b3, int c3){
    return f(a1, a2, a3) * f(b1, b2, b3) * f(c1, c2, c3);
}

int V2(int a1, int b1, int c1, int a2, int b2, int c2, int a3, int b3, int c3){
    int u = f(a1, a2) * f(b1, b2) * f(c1, c2), v = f(a1, a3) * f(b1, b3) * f(c1, c3);
    int w = f(a2, a3) * f(b2, b3) * f(c2, c3);
    return u + v + w;
}


int main(){
    cin >> a >> b >> c;
    if(a + b * 2 + c * 3 != 1029) cout << "No" << endl;
    else{
        for(int a1 = 0; a1 <= 7; a1++)
        for(int b1 = 0; b1 <= 7; b1++)
        for(int c1 = 0; c1 <= 7; c1++)
        for(int a2 = 0; a2 <= 7; a2++)
        for(int b2 = 0; b2 <= 7; b2++)
        for(int c2 = 0; c2 <= 7; c2++)
        for(int a3 = 0; a3 <= 7; a3++)
        for(int b3 = 0; b3 <= 7; b3++)
        for(int c3 = 0; c3 <= 7; c3++){
            int v3 = V3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
            if(v3 != c) continue;
            int v2 = V2(a1, a2, a3, b1, b2, b3, c1, c2, c3) - v3 * 3;
            if(v2 != b) continue;
            cout << "Yes" << endl;
            cout << a1 << " " << a2 << " " << a3 << " " << b1 << " " << b2 << " " << b3 << " " << c1 << " " << c2 << " " << c3 << endl;
            return 0;
        }
    }
    return 0;
}

F - Second Largest Query

大意

n个数A_i, q个询问 ,分两种:

  • 1 p x,将A_p=x
  • 2 l r,问A_{l\cdots r}中次大值的出现次数

思路

使用线段树,维护四个信息:

  • 最大值
  • 最大值的出现次数
  • 次大值
  • 次大值的出现次数

代码

#include<iostream>
#include<vector>
using namespace std;
#define int long long

struct segment{
    struct Node{
        int l, r;
        int mx1, cnt1;
        int mx2, cnt2;
    };

    vector<Node> tr;
    Node merge(Node a, Node b){
        Node ans = {0, 0, 0, 0, 0, 0};
        ans.mx1 = max(a.mx1, b.mx1);
        ans.mx2 = max(
            max(ans.mx1 != a.mx1? a.mx1: 0, ans.mx1 != b.mx1? b.mx1: 0),
            max(a.mx2, b.mx2));
        if(ans.mx1 == a.mx1) ans.cnt1 += a.cnt1;
        if(ans.mx1 == b.mx1) ans.cnt1 += b.cnt1;
        if(ans.mx2 == a.mx1) ans.cnt2 += a.cnt1;
        if(ans.mx2 == b.mx1) ans.cnt2 += b.cnt1;
        if(ans.mx2 == a.mx2) ans.cnt2 += a.cnt2;
        if(ans.mx2 == b.mx2) ans.cnt2 += b.cnt2;
        return ans;
    }

    void pushup(int u){
        Node ans = merge(tr[u << 1], tr[u << 1 | 1]);
        tr[u] = {tr[u].l, tr[u].r, ans.mx1, ans.cnt1, ans.mx2, ans.cnt2};
    }

    void build(int u, int l, int r, vector<int> &a){
        tr[u].l = l, tr[u].r = r;
        if(l == r) tr[u].mx1 = a[l - 1], tr[u].cnt1 = 1;
        else{
            int mid = l + r >> 1;
            build(u << 1, l, mid, a), build(u << 1 | 1, mid + 1, r, a);
            pushup(u);
        }
    }

    segment(vector<int> &a){
        tr.assign(a.size() << 2, {0, 0, 0, 0, 0, 0});
        build(1, 1, a.size(), a);
    }

    void modify(int u, int x, int k){
        if(tr[u].l == tr[u].r) tr[u].mx1 = k, tr[u].cnt1 = 1;
        else{
            int mid = tr[u].l + tr[u].r >> 1;
            if(x <= mid) modify(u << 1, x, k);
            else modify(u << 1 | 1, x, k);
            pushup(u);
        }
    }

    Node query(int u, int l, int r){
        if(tr[u].l >= l && tr[u].r <= r) return tr[u];
        Node ans = {0, 0, 0, 0, 0, 0};
        int mid = tr[u].l + tr[u].r >> 1;
        if(l <= mid) ans = merge(ans, query(u << 1, l, r));
        if(mid < r) ans = merge(ans, query(u << 1 | 1, l, r));
        pushup(u);
        return ans;
    }
};



signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
	vector<int> a(n);
    for(auto &x: a) cin >> x;
	segment seg(a);
	while(m--){
        int op, l, r;
		cin >> op >> l >> r;
		if(op == 1) seg.modify(1, l, r);
		else{
			auto ans = seg.query(1, l, r);
			cout << ans.cnt2 << endl;
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值