AtCoder Beginner Contest 365 補題記錄(A~E,G)

yhbqwq發表於2024-08-03

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;
}

相關文章