• Codeforces Round #490 (Div. 3) 訓練總結及題解


    这场AB很快就秒了,C没读懂题,D也没读懂,开了E题,wa了2发之后休息了一会开始做CD,C很简单过了,然后继续怼E,wa了1发,开始看F然后开D,最后DE切换,后来发现Dwa3发是爆了int。E一直想拿并查集做懒得写tarjan,补题的时候发现了并查集的bug,最后还是拿了tarjan写。F题场后发现居然可以这样dp。
    总结:

    1. 读不懂切题挺好的。
    2. 还是要注意ll
    3. D的前两wa,一个是TLE的算法没注意看数据,一个是没写好一个地方,也记录错误cnt里。

    题解:
    A.
    题意:n个数,从两头删除权值<=k的数,问最多能删几个。(n,k都很小
    思路:一开始写的双指针,后来写了一半想写deque了。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    
    int main(){
        IO;
        int n,k;cin>>n>>k;
        deque<int>q;forn(i,n){
            int x;cin>>x;
            q.push_back(x);
        }int cnt = 0;
        while(!q.empty()){if(q.front()>k&&q.back()>k)break;
            if(q.front()<=k) cnt++,q.pop_front();
            else if(q.back()<=k) cnt++,q.pop_back();
            
        }
        cout << cnt <<'
    ';
    
    
    
    
    
    
    
    
        return 0;
    }
    

    B
    題意:一個字符串長度n,設x屬於1-n,如果n可以被x整除那麽把1-x位倒過來。按因子逆序的方式倒過來的字符串是加密字符串,讓你解碼。(n很小
    思路:暴力
    代碼:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    
    int main(){
        IO;
        int n;string s;cin>>n>>s;
        for1(i,n)if(n%i==0){
            string t = "";
            for(int j = i-1;j>=0;j--){
                t+=s[j];
            }
            for(int j = i;j<n;j++){
                t+=s[j];
            }
            s = t;
        }
        cout << s<<'
    ';
    
        return 0;
    }
    

    C
    題意:長度為n的字符串,k次操作,先按字典序刪除字符再按1-n刪除的順序刪除k次,問之後最後字符串變成什麽。
    思路:圖方便用的multiset
    代碼:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    
    int main(){
        IO;
        multiset<pair<char,int> >s;
        multiset<pair<int,char> > s2;
        int n,k;cin>>n>>k;
        forn(i,n){
            char c;cin>>c;
            s.insert({c,i});
        }
        forn(i,k){
            s.erase(s.begin());
        }
        for(auto x:s){
            s2.insert({x.second,x.first});
        }
        for(auto x:s2) cout <<x.second;
        return 0;
    }
    

    D.
    題意:n被m整除,給你n個數,一次操作可以讓a[i]++,讓你使這n個數通過最小的操作次數使得每個a[i]%m后的數的cnt==n/m
    思路:lowerbound
    代碼:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(ll i=0;i<n;i++)
    #define for1(i,n) for(ll i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    const ll inf = 0x3f3f3f3f;
    map<ll,ll>mp;
    
    int main(){
        IO;
        ll n,m;cin>>n>>m;
        ll lim = n/m;
        vector<ll>a(n);
        set<ll>s;
        forn(i,m) s.insert(i);
        s.insert(inf);
        ll cnt = 0;
        forn(i,n){
            cin>>a[i];
            ll x = a[i]%m;
            if(mp[x]<lim) mp[x]++;
            else{
                if(*s.lower_bound(x)!=inf){
                    ll y = *s.lower_bound(x);
                    cnt+=y-x;
                    a[i]+=y-x;
                    mp[y]++;
                    x = y;
                }else{
                    ll y = *s.lower_bound(0);
                    cnt+=m-(x-y);
                    a[i]+=m-(x-y);
                    mp[y]++;
                    x = y;
                }
            }
            if(mp[x]==lim) s.erase(x);
        }cout<<cnt<<'
    ';
        for(auto x:a)cout<<x<<' ';
    
    
    
    
    
    
    
    
    
        return 0;
    }
    

    E.
    題意:给定三个正整数N,M,S,N表示图中一共有N个节点,M表示有M条边,S是N个节点中的一个,并给定M条单向边,求至少需要加几条单向边,使得从S出发,能够到达所有其他节点。
    思路:我是tarjan縮點完找入度為0的點
    代碼:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    const int maxn = 5005;
    int low[maxn],dfn[maxn],id,color[maxn],cnt,tim[maxn];
    vector<int>e[maxn],g[maxn];
    stack<int>s;
    void tarjan(int u){
        low[u] = dfn[u] = ++id;
        s.push(u);
        for(auto v:e[u]){
            if(!dfn[v]){
                tarjan(v);
                low[u] = min(low[u],low[v]);
            }else if(!color[v]){
                low[u] = min(low[u],dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            cnt++;
            while(1){
                int x = s.top();s.pop();
                color[x] = cnt;
                if(x==u)break;
            }
        }
    }
    
    int main(){
        IO; 
        int n,m,s;cin>>n>>m>>s;
        forn(i,m){
            int u,v;cin>>u>>v;
            e[u].push_back(v);
        }
        tarjan(s);
        for1(i,n)if(!dfn[i]) tarjan(i);
        s = color[s];
        for1(i,n)if(!e[i].empty()){
            int u = color[i];
            for(auto x:e[i]){
                int v = color[x];
                if(u==v)continue;
                g[u].push_back(v);
                tim[v]++;
            }
        }
        int ans = 0;
        for1(i,cnt)if(!tim[i]&&i!=s) ans++;
        cout << ans <<'
    ';
        return 0;
    }
    

    F.
    題意:n500個人,要從nk張權值範圍(1-1e5)的牌中抽取k10張,每個人有自己喜愛的牌fi,如果手中有x張自己喜愛的牌那麽他的貢獻就爲hx。問所有人貢獻最大值多少。
    思路:預處理dp,因爲每個人貢獻只跟自己喜愛的牌有關,所以可以貪心,但是問題在於有幾個人遇到了相同的牌,比如h0-4為1 2 3 10000,現在兩個人都喜歡一張牌,那麽40分其實貢獻最高。
    所以dp預處理dpij
    i為i個人重複,j為n
    m個物品
    代碼:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    const int maxn = 1e5+5;
    int num[maxn],f[maxn],h[11],dp[505][5500];
    
    int main(){
        IO;
        int n,k;cin>>n>>k;
        forn(i,n*k){
            int x;cin>>x;
            num[x]++;
        }
        forn(i,n){
            int x;cin>>x;
            f[x]++;
        }
        for1(i,k){
            cin>>h[i];
        }
        forn(i,n){
            forn(j,n*k){
                for1(z,k){
                    dp[i+1][j+z] = max(dp[i+1][j+z],dp[i][j]+h[z]);
                }
            }
        }
        ll ans = 0;
        for1(i,maxn)if(f[i]){
            ans+=dp[f[i]][num[i]];
        }
        cout << ans <<'
    ';
        return 0;
    }
    
    人一我百,人十我万。
  • 相关阅读:
    javascript实现简单的轮播图片
    用struts实现简单的登录
    非非是
    javabean连数据库
    超级迷宫 nabc
    我的Time
    SQL SERVER 2008 评估期已过
    《架构漫谈》有感
    c#
    与String有关的强制转换
  • 原文地址:https://www.cnblogs.com/AlexPanda/p/12520315.html
Copyright © 2020-2023  润新知