2024牛客暑期多校訓練營2 解題報告

archer2333發表於2024-07-20

B-MST
對於整個序列進行一次kruskal
對於序列中 如果需要訪問的點數小於300
那麼將所有的點的邊存入序列中進行kruskal
如果大於300
那麼直接對於所有的點進行kruskal

點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=998244353;
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
int fac[100005],ifac[100005];
const int N=1e5+10;
int f[N];
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}
unordered_map<int,int>mp[N];
bool merge(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx==fy)return false;
    f[fy]=fx;
    return true;
}
struct Link{
    int x,y,w;
}L[N];
int n,m,q;
int h,vis[N];
void Solve(){
    cin>>h;
    vector<int>a(h);
    for(int i=0;i<h;i++)cin>>a[i],f[a[i]]=a[i];
    int ans=0;
    int sz=h;
    if(h>=300){
        for(auto x:a)vis[x]=1;
        for(int i=1;i<=m;i++){
            if(vis[L[i].x]&&vis[L[i].y]){
                if(merge(L[i].x,L[i].y)){
                    ans+=L[i].w;
                    sz--;
                }
            }
        }
        for(auto x:a)vis[x]=0;
    }else {
        sort(a.begin(),a.end());
        vector<int>e;
        for(int i=0;i<h;i++){
            int x=a[i];
            for(int j=i+1;j<h;j++){
                int y=a[j];
                if(mp[x].count(y))e.pb(mp[x][y]);
            }
        }
        sort(all(e));
        for(auto i:e){
            if(merge(L[i].x,L[i].y)){
                ans+=L[i].w;
                sz--;
            }
        }
    }
    if(sz==1){
        cout<<ans<<'\n';
    }else cout<<-1<<'\n';


}
void solve(){

    cin>>n>>m>>q;
    for(int i=1;i<=m;i++){
        cin>>L[i].x>>L[i].y>>L[i].w;
        if(L[i].x>L[i].y)swap(L[i].x,L[i].y);
    }
    sort(L+1,L+m+1,[&](Link a,Link b){return a.w<b.w;});
    for(int i=1;i<=m;i++){
        if(!mp[L[i].x].count(L[i].y)){
            mp[L[i].x][L[i].y]=i;
        }
    }
    while(q--)Solve();
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int _=1;
//    cin>>_;
    while(_--)solve();
}
C-Red Walking on Grid 透過觀察可以得知對於前一個點 如果前兩個點為R 那麼當前節點 直接考慮字首最優 如果只有當前一個點為R 那麼選擇繼承前一個點的最優 如果全為W 則不用繼承
點選檢視程式碼
#include<bits/stdc++.h>

#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
const int N=1e6+10;
using namespace std;
const int mod = 998244353;
vector<vector<char> >a(N,vector<char>(2));
vector<vector<int> >dp(N,vector<int>(2));
void solve() {
    int n;
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i][0];
    }
    for(int i=1;i<=n;i++){
        cin >> a[i][1];
    }
    a[0]={'W','W'};
    a[n+1]={'W','W'};
    int mx=0;
    for(int i=1;i<=n;i++){
        int w0=dp[i-1][0];
        int w1=dp[i-1][1];
        if(a[i][0]=='R'&&a[i][1]=='R'){
            dp[i][0]=max(w0+1,w1+2);
            dp[i][1]=max(w1+1,w0+2);
        }else if(a[i][0]=='R'){
            dp[i][0]=w0+1;
        }else if(a[i][1]=='R'){
            dp[i][1]=w1+1;
        }

        mx=max({mx,dp[i][0],dp[i][1]});
    }
    int ans=0;
    cout <<max(mx-1,ans);
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int _ = 1;
//    cin>>_;
    while (_--)solve();
}
E-GCD VS XOR 透過觀察得知直接lowbit即可
點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=1e9+7;
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
int fac[100005],ifac[100005];
void qjc(int n){
    fac[0]=1;
    for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    ifac[n]=inv(fac[n]);
    for(int i=n-1;i>=1;i--)ifac[i]=ifac[i+1]*(i+1)%mod;
    ifac[0]=1;
}
int C(int m,int n){return fac[m]*ifac[m-n]%mod*ifac[n]%mod;}
void solve(){
    int x;cin>>x;
    int res=x&-x;
    if(x-res==0){
        cout<<-1<<'\n';
    }else cout<<x-res<<'\n';
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int _=1;
    cin>>_;
    while(_--)solve();
}

H-Instructions Substring
透過觀察得知
每個序列能否滿足情況
即為對於字首和pre[i]
pre[i]-pre[j]==x
這時即可滿足情況
對於前面每組滿足情況的經過
後面所有的情況都可以滿足
所有乘完只會需要清空map中儲存的狀態

點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=998244353;
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
int fac[100005],ifac[100005];
void qjc(int n){
    fac[0]=1;
    for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    ifac[n]=inv(fac[n]);
    for(int i=n-1;i>=1;i--)ifac[i]=ifac[i+1]*(i+1)%mod;
    ifac[0]=1;
}
int C(int m,int n){return fac[m]*ifac[m-n]%mod*ifac[n]%mod;}
int prex[200005]={0};int prey[200005]={0};
map<pii,int>mp;map<pii,int>cnt;map<pii,int>mins;
void solve(){
    int n,x,y;cin>>n>>x>>y;
    string s;cin>>s;
    for(int i=1;i<=n;i++){
        if(s[i-1]=='D'){
            prex[i]=prex[i-1]+1;
            prey[i]=prey[i-1];
        }
        else if(s[i-1]=='A'){
            prex[i]=prex[i-1]-1;
            prey[i]=prey[i-1];
        }
        else if(s[i-1]=='S'){
            prex[i]=prex[i-1];
            prey[i]=prey[i-1]-1;
        }else if(s[i-1]=='W'){
            prex[i]=prex[i-1];
            prey[i]=prey[i-1]+1;
        }
    }
    int ans=0;
    if(x==0&&y==0){
        cout<<n*(n+1)/2<<'\n';return;
    }
    for(int i=0;i<=n;i++){
        cnt[{x+prex[i] ,y+prey[i]}]++;
//        if(x==0&&y==0&&i>0){
//            ans+=n-i+1;
//            continue;
//        }
        if(i>0)ans+=(cnt[{prex[i],prey[i]}])*(n-i+1),cnt[{prex[i],prey[i]}]=0;
//        cout<<ans<<'\n';
    }
    cout<<ans<<'\n';
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int _=1;
//    cin>>_;
    while(_--)solve();
}
H-Red Playing Cards 按照數字從大到小進行刪除 其中對於每個區間取最大 賽時未想出如何將首尾進行合併 其實只需要將首位加0 在進行一次操作即可
點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=998244353;
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
int fac[100005],ifac[100005];
void qjc(int n){
    fac[0]=1;
    for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    ifac[n]=inv(fac[n]);
    for(int i=n-1;i>=1;i--)ifac[i]=ifac[i+1]*(i+1)%mod;
    ifac[0]=1;
}
int C(int m,int n){return fac[m]*ifac[m-n]%mod*ifac[n]%mod;}
const int N=3e3+10;
const int M=1e5+10;
int tr[M];
int query(int x){
    int ans=0;
    while(x){
        ans+=tr[x];
        x-=x&-x;
    }
    return ans;
}
void add(int x,int v){
    while(x<=M-10){
        tr[x]+=v;
        x+=x&-x;
    }
}
int dp[N];
int l[N],r[N];
int len[N];
int vis[N*2];
int g[M];
int f[M];
void solve(){
    int n;cin>>n;
    vector<int>a(2*n+10);
    memset(dp,0,sizeof(dp));
    int m=n;
    n=n*2+2;
    for(int i=2;i<=n-1;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++){
        if(!l[a[i]])l[a[i]]=i;
        else r[a[i]]=i;
    }
    for(int i=m;i>=0;i--){
        int L=l[i],R=r[i];
        for(int j=L-1;j<=R;j++)g[j]=0;
        for(int j=L;j<=R;j++){
            g[j]=g[j-1]+i;
            if(a[j]>i&&j==r[a[j]]){
                int k=l[a[j]];
                if(k>=L){
                    g[j]=max(g[j],g[k-1]+f[a[j]]);
                }
            }
        }
        f[i]=g[R];
    }
    cout<<f[0];
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    int _=1;
//    cin>>_;
    while(_--)solve();
}

相關文章