AtCoder Beginner Contest 343(A~D and F)

A - Wrong Answer

输出0~9里面任何一个不等于A+B的。

B - Adjacency Matrix 

给你一个矩阵

给你一个无向图,对应的Ai,j=1,那么代表i,j连在一起。

第 i 行,按升序输出跟 i 节点连接的节点。

#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define debug(a) cout<<#a<<"="<<a<<endl
#define fr first
#define se second
#define endl '\n'
using namespace std;

void solve(){
    int n;
    cin>>n;
    per(i,1,n){
        per(j,1,n){
            int tmp;
            cin>>tmp;
            if(tmp)cout<<j<<" ";
        }cout<<endl;
    }
}

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

C - 343

找到一个 最大的(小于等于N) 满足特殊条件(两个如下)的 数K。

1、是一个立方数,即 K=x^3

2、是一个回文数。

N<=1e18,直接枚举立方数只需要到1e6,判断回文数也很快,总复杂度不会超,直接枚举立方数就行了。

#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define debug(a) cout<<#a<<"="<<a<<endl
#define fr first
#define se second
#define endl '\n'
using namespace std;

void solve(){
    int n;
    cin>>n;

    int ans=1;

    auto check=[&](int x){
        vector<int>a;
        a.push_back(1);
        while(x){
            a.push_back(x%10);
            x/=10;
        }
        int n=a.size()-1;
        per(i,1,n/2){
            if(a[i]!=a[n-i+1])
                return false;
        }
        return true;
    };

    per(i,1,1e8){
        int x=i*i*i;
        if(x>n)break;
        if(check(x))ans=x;
    }

    cout<<ans;
}

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

D - Diversity of Scores

N个玩家,T次操作,每次操作为 Ai 玩家加 Bi 分。

每次操作后输出当前不同的分数数量。

比如一开始为{0,0,0} 只有一种分数0

假设第一次操作为第一个玩家加一分,那么为{1,0,0}有两种不同分数,1和0,则输出2

简单思考一下应该是不可以每次都去数一遍不同的数量,会超时。

考虑动态修改,每次做到O(1)输出。

则用map来记录一下当前分数的数量。

#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define debug(a) cout<<#a<<"="<<a<<endl
#define fr first
#define se second
#define endl '\n'
using namespace std;

const int T=2e5+5;
int n,t,a[T],b[T];

void solve(){

    cin>>n>>t;
    per(i,1,t)cin>>a[i]>>b[i];

    map<int,int>f;//分数有几个

    f[0]=n;
    int s[T];//模拟分数
    per(i,1,n)s[i]=0;

    int now=1;

    per(i,1,t){

//        for(auto [x,y]:f){
//            cout<<x<<" "<<y<<endl;
//        }cout<<endl;

        f[s[a[i]]]--;
        if(f[s[a[i]]]==0)now--;
        s[a[i]]+=b[i];
        if(f[s[a[i]]]==0)now++;
        f[s[a[i]]]++;

        cout<<now<<endl;
    }
}

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

这里需要注意的是,map<int,int>f,f[5]=1,执行f[5]--之后,f[5]是存在的,即f[5]=0,使用f.size()输出是不合法的。

F - Second Largest Query 

给你一个数组a1,a2,a3,...,an,Q个询问,每个询问进行下面的操作。

1、询问格式为:1 p x,将ap的值改为x

2、询问格式为:2 l r,查询数组下标范围[l,r]中第二大数出现的次数。

N,Q<=2e5

直接模拟,大量查询复杂度能到N*Q,要用log级别的算法或者结构来优化,Q省不了,只能N变成logN,考虑线段树。

后序遍历传递的信息为最大值,最大值出现的次数,次大值,次大值出现的次数。

记录用map<值,次数>,然后逆序把map的值赋值给父亲节点。

线段树的查询单点修改都是logN,做这道题的时候修改忘记加x<=mid和y>mid导致单点修改成NlogN了,牛魔。

#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define debug(a) cout<<#a<<"="<<a<<endl
#define fr first
#define se second
#define endl '\n'
using namespace std;
const int N=2e5+5;

int a[N];
struct Node{
    int max,max2;//第一大 第二大
    int cnt,cnt2;
}seg[N<<2];

int lc(int i){
    return i<<1;
}

int rc(int i){
    return i<<1|1;
}

void update(int i){
    map<int,int>f;
    f[seg[lc(i)].max]+=seg[lc(i)].cnt;
    f[seg[lc(i)].max2]+=seg[lc(i)].cnt2;
    f[seg[rc(i)].max]+=seg[rc(i)].cnt;
    f[seg[rc(i)].max2]+=seg[rc(i)].cnt2;

    auto it=f.rbegin();
    seg[i].max=(*it).fr;
    seg[i].cnt=(*it).se;
    it++;
    seg[i].max2=(*it).fr;
    seg[i].cnt2=(*it).se;
}

void build(int l,int r,int i){
    if(l==r){
        seg[i].max=a[l];
        seg[i].max2=0;
        seg[i].cnt=1;
        seg[i].cnt2=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,lc(i));
    build(mid+1,r,rc(i));
    update(i);
}

void change(int l,int r,int i,int p,int x){
    if(l==r){
        if(l==p){
            seg[i].max=x;
        }
        return;
    }

    int mid=(l+r)>>1;
    if(p<=mid)change(l,mid,lc(i),p,x);
    if(p>mid)change(mid+1,r,rc(i),p,x);
    update(i);
}

map<int,int>g;

void query(int l,int r,int i,int x,int y){
    if(l>=x and r<=y){
        g[seg[i].max]+=seg[i].cnt;
        g[seg[i].max2]+=seg[i].cnt2;
        return;
    }

    int mid=(l+r)>>1;
    if(x<=mid)query(l,mid,lc(i),x,y);
    if(y>mid)query(mid+1,r,rc(i),x,y);
}

void solve(){
    int n,q;
    cin>>n>>q;
    per(i,1,n)cin>>a[i];

    build(1,n,1);


    int cnt=0;
    per(i,1,q){
        int opt,p,x,l,r;
        cin>>opt;
        if(opt==1){
            cin>>p>>x;
            change(1,n,1,p,x);
        }else{
            cin>>l>>r;

            g.clear();
            query(1,n,1,l,r);

            auto it=g.rbegin();
            it++;
            cout<<(*it).se<<endl;
        }
    }
}

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

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值