AtCoder Beginner Contest 365 补题记录(A~E,G)

Perf 2000+,但是补不回来上场超低的 Rating/ll

A

#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
    int n;
    cin>>n;
    if(n%400==0)cout<<"366\n";
    else if(n%100==0)cout<<"365\n";
    else if(n%4==0)cout<<"366\n";
    else cout<<"365\n";
    return 0;
}

B

开个结构体排序即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100;
struct qwq{
    int x,id;
    bool operator<(const qwq&r)const{
        return x>r.x;
    }
}a[N];
signed main(){
    int n;cin>>n;
    for(int i=1;i<=n;++i)cin>>a[i].x,a[i].id=i;
    sort(a+1,a+n+1);
    cout<<a[2].id<<'\n';
    return 0;
}

C

简单题。二分答案 \(p\),那么补贴即为 \(\sum\limits_{i=1}^n\min(a_i,p)\),直接计算一下然后找到最大的满足条件的 \(p\) 即可。时间复杂度为 \(O(n\log n)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100;
int a[N],n,m;
bool check(int p){
    __int128 re=0;
    for(int i=1;i<=n;++i)
        re+=min(p,a[i]);
    return re<=m;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;++i)cin>>a[i];
    int s=0;
    for(int i=1;i<=n;++i)s+=a[i];
    if(s<=m)cout<<"infinite\n";
    else{
        int l=0,r=3e14,best=0;
        while(l<=r){
            int mid=l+r>>1;
            if(check(mid))best=mid,l=mid+1;
            else r=mid-1;
        }
        cout<<best<<'\n';
    }
    return 0;
}

D

\(f_{i,0/1/2}\) 表示当前出到第 \(i\) 拳,当前 Takahashi 出的拳是 R,P,S,最多可以赢多少局。

然后 \(f_{1,0/1/2}\) 特殊计算一下,\(f_{i,j}\) 的值可以通过 \(f_{i-1,k}\) 转移来当且仅当 \(j\neq k\),取一个最大值然后增加对答案的贡献即可。时间复杂度为 \(O(n)\)

容易发现本题必然有解。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100;
int a[N],n,m;
int box[N];
int f[N][3];
//f[i][0/1/2]:R/P/S
//R win S
//S win P
//P win R
signed main(){
    cin>>n;
    string s;
    cin>>s;
    s=' '+s;
    if(s[1]=='R'){
        f[1][0]=0;
        f[1][1]=1;
        f[1][2]=-1e18;
    }else if(s[1]=='P'){
        f[1][0]=-1e18;
        f[1][1]=0;
        f[1][2]=1;
    }else{
        f[1][0]=1;
        f[1][1]=-1e18;
        f[1][2]=0;
    }
    for(int i=2;i<=n;++i){
        if(s[i]=='R'){
            f[i][0]=max({f[i-1][1],f[i-1][2]});
            f[i][1]=max({f[i-1][0],f[i-1][2]})+1;
            f[i][2]=-1e18;
        }else if(s[i]=='P'){
            f[i][0]=-1e18;
            f[i][1]=max({f[i-1][0],f[i-1][2]});
            f[i][2]=max({f[i-1][0],f[i-1][1]})+1;
        }else{
            f[i][0]=max({f[i-1][1],f[i-1][2]})+1;
            f[i][1]=-1e18;
            f[i][2]=max({f[i-1][0],f[i-1][1]});
        }
    }
    cout<<max({f[n][0],f[n][1],f[n][2]})<<'\n';
    return 0;
}

E

这不是灵茶八题 T3?

看到异或就想到拆位计算答案。设当前枚举到第 \(k\) 位,这一位有 \(i\)\(0\)\(j\)\(1\),因为异或为 \(1\) 要求两个异或的数互不相同,所以这一位对答案的贡献即为 \(i\times j\times 2^k\)

将所有位对答案的贡献累加即可。时间复杂度为 \(O(n\log W)\)

void solve(){
    int n;cin>>n;
    for(int i=1;i<=n;++i)cin>>a[i],s[i]=a[i],a[i]^=a[i-1];
    int res=0;
    for(int k=0;k<30;++k){
        int cnt=0;
        for(int j=0;j<=n;++j)cnt+=a[j]>>k&1;
        res+=cnt*(n-cnt+1)*(1ll<<k);
    }
    for(int i=1;i<=n;++i)res-=s[i];
    cout<<res<<'\n';
}

F

看上去很难写,但是不会。

G

看到 \(2\times 10^5\)\(5\) seconds,立马想到 \(O(n\sqrt n\log n)\) 算法!因此想到根号分治。

将所有员工分类:若员工 \(i\) 进入了房间超过 \(\sqrt m\) 次那么称为一类员工,否则称为二类员工。

对所有的一类员工都开一个动态开点线段树,也就是开最多 \(\sqrt m\) 个动态开点线段树。

然后暴力枚举任意两个一类员工并直接暴力合并信息计算答案。这个部分是 \(O(m\sqrt m\log m)\) 的。

然后考虑 \(Q\) 次查询:

  • 若两个员工均为一类员工,则直接套直接计算的答案,可以用一个 map 存储。
  • 若两个员工均为二类员工,则直接暴力计算答案。
  • 若一个员工为一类员工另一个为二类员工,则考虑暴力枚举二类员工的每一次进入的区间,然后找到一类员工所对应的动态开点线段树并区间查询找到重复的数量并求和。这个部分时间复杂度为 \(O(\sqrt m\log m)\)

因为代码还没有调出来所以就先不放代码了。

upd:AtCoder 你是【人的一个器官】吗,不放 \(O(n\sqrt n\log n)\) 过放 \(O(n^2)\) 过。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
const int N=200100;
int t[N],p[N],a[N],b[N];
int on[N];
vector<pair<int,int>>z[N];
signed main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;++i){
        int t,p;cin>>t>>p;
        if(!on[p])on[p]=t;
        else z[p].emplace_back(t,on[p]),on[p]=0;
    }
    for(int i=1;i<=n;++i)
        sort(z[i].begin(),z[i].end());
    int q;cin>>q;
    map<pair<int,int>,int>mp;
    while(q--){
        int l,r,res=0;cin>>l>>r;
        if(mp[{l,r}])cout<<mp[{l,r}]<<'\n';
        else{
            for(int i=0;i<z[r].size();++i)
            for(int j=z[l].size()-1;~j;--j){
                auto[r1,l1]=z[l][j];
                auto[r2,l2]=z[r][i];
                if(max(l1,l2)<=min(r1,r2))res+=min(r1,r2)-max(l1,l2);
                else if(r1<l2)break;
            }
            cout<<(mp[{l,r}]=res)<<'\n';
        }
    }
    return 0;
}
posted @ 2024-08-03 22:13  yhbqwq  阅读(261)  评论(1编辑  收藏  举报