Codeforces Round #590 (Div. 3) 訓練總結及A-F題解

總結:A5mins ac,B過的慢22mins ac,接着就被c卡了一小時1小時ac,寫到了d題,因爲打星練了下手速,無板子17mins ac還算不錯,e是個差分,f思維題。
總結:

  1. C題想多一點,就節省了很多代碼量。
  2. E題要靜下心寫。

題解:
A.
題意:00個貨物,價格不一。使所有貨物價格變爲一個價格,且新總價格>=原sum且要求變動最小。
思路:-1找到平均值+1
代碼:

#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)
const int inf = 2e9+5;
const ll INF = 2e18+5;

int main(){
    IO;cout.precision(10);cout<<fixed;  
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        int sum = 0;
        forn(i,n){
            int x;cin>>x;
            sum+=x;
        }
        sum--;
        sum/=n;
        sum++;
        sum;
        cout<<sum<<'\n';
    }
    return 0;
}

B.
題意:2e5個數,你的顯示器每次只能顯示k個數,按順序來如果新來的數字在顯示器上,則不更新顯示器,如果超過k個數,擠掉顯示器進入最早的數。
思路:維護一個set來確定進不進,維護一個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)
const int inf = 2e9+5;
const ll INF = 2e18+5;

int main(){
    IO;cout.precision(10);cout<<fixed;  
    set<int>s;
    deque<int>ans;
    int n,k;cin>>n>>k;
    forn(i,n){
        int x;cin>>x;
        if(s.find(x)!=s.end()) continue;
        if(ans.size()<k){
            s.insert(x);
            ans.push_back(x);
            continue;
        }
        int y = ans.front();ans.pop_front();
        s.erase(s.find(y));
        s.insert(x);ans.push_back(x);
    }
    cout<< ans.size() <<'\n';
    while(!ans.empty()){
        cout<<ans.back()<<' ';
        ans.pop_back();
    }
    return 0;
}

C
題意:如圖從左上走到右下,地圖大小2*n(n2e5),每個管道可以旋轉。問能否走出去。在這裏插入圖片描述
思路:bfs或者按順序走就可以。
代碼:

#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)
const int inf = 2e9+5;
const ll INF = 2e18+5;
struct node{
    int x,y,p;
};
const int maxn = 2e5+5;

bool vis[2][maxn];
int dy[] = {0,0,1},dx[] = {1,-1,0};

int main(){
    IO;cout.precision(10);cout<<fixed;  
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        string s[2];cin>>s[0]>>s[1];
        queue<node>q;
        node now = {0,0,2};
        bool ok = 0;
        q.push(now);
        while(!q.empty()){
            now = q.front();q.pop();
            int x = now.x,y = now.y,p = now.p;
            //cerr<<"@!#!@#   "<<x<<' '<<y<<'\n';
            if(x==1&&y==n-1){
                //cerr<<"@!@!#@!#@!   "<<s[x][y]<<' '<<p<<'\n';
                if(s[x][y]>='1'&&s[x][y]<='2'){
                    if(p==2) ok = 1;
                }else{
                    if(p==0) ok = 1; 
                }
            }
            if(s[x][y]>='1'&&s[x][y]<='2'){
                if(p!=2) continue;
                int nx = x+dx[2],ny = y+dy[2];
                if(nx<0||nx>1||ny<0||ny==n)continue;
                if(vis[nx][ny]) continue;
                vis[nx][ny] = 1;
                q.push({nx,ny,2});
            }else{
                if(p!=2){
                    int nx = x+dx[2],ny = y+dy[2];
                    if(nx<0||nx>1||ny<0||ny==n)continue;
                    if(vis[nx][ny]) continue; 
                    vis[nx][ny] = 1;
                    q.push({nx,ny,2});
                }else{
                    forn(i,2){
                        int nx = x+dx[i],ny = y+dy[i];
                        if(nx<0||nx>1||ny<0||ny==n)continue;
                        if(vis[nx][ny]) continue; 
                        vis[nx][ny] = 1;
                        q.push({nx,ny,i});
                    }
                }
            }
        }
        if(!ok) cout<<"NO"<<'\n';
        else cout<<"YES"<<'\n';
        forn(i,2) forn(j,n) vis[i][j] = 0;
    }
    return 0;
}

D.
題意:1e5的字符串,兩種操作:1.修改某位置字符 2.查詢區間字符不相同數。
思路:線段樹,字母表對應二進制的位數,用或操作。
代碼:

#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)
const int inf = 2e9+5;
const ll INF = 2e18+5;
const int maxn = 1e5+5;

int a[maxn],n,now;
class segment_tree{
    public:
    #define nd node[now]
    #define ndl node[now<<1]
    #define ndr node[now<<1|1]
    struct segement_node{
        int l,r,v;
    }node[maxn<<2];
    void pushup(int now){
        nd.v = ndl.v|ndr.v;
    }
    void maketree(int l,int r,int now = 1){
        nd = {l,r,0};
        if(l==r){
            nd.v = (1<<a[l]);
            return;
        } 
        maketree(l,l+r>>1,now<<1);
        maketree((l+r>>1)+1,r,now<<1|1);
        pushup(now);
    }
    void update(int pos,int v,int now = 1){
        if(nd.l==nd.r){
            nd.v = (1<<v);
            return;
        }
        if(pos<=ndl.r) update(pos,v,now<<1);
        else update(pos,v,now<<1|1);
        pushup(now);
    }
    int query(int l,int r,int now = 1){
        if(l<=nd.l&&r>=nd.r) return nd.v;
        int res = 0;
        if(l<=ndl.r) res|=query(l,r,now<<1);
        if(r>=ndr.l) res|=query(l,r,now<<1|1);
        return res;
    }
}tree;

int main(){
    IO;cout.precision(10);cout<<fixed;  
    string s;cin>>s;
    n = s.size();
    for1(i,n) a[i] = s[i-1]-'a';
    tree.maketree(1,n);
    int q;cin>>q;
    while(q--){
        int op;cin>>op;
        if(op==1){
            int pos;char c;cin>>pos>>c;
            int v = c-'a';
            tree.update(pos,v);
        }else{
            int l,r;cin>>l>>r;
            int x = tree.query(l,r),res = 0;
            forn(i,26){
                int y = 1<<i;
                if(x&y) res++;
            }
            cout<<res<<'\n';
        }
    }
    return 0;
}

E
題意:從1-n的序列,pi(n)函數會把序列中第i個值提出來放到序列第一位。然後告訴你一個pos(pi,xi)函數,會找到pi序列的第xi個值,xi是給定的數組,再告訴你一個F函數,求1-n每個f函數的值。具體函數看題目。
思路:分類討論,然後差分
代碼:

#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)
const int inf = 2e9+5;
const ll INF = 2e18+5;
const int maxn = 2e5+5;

int a[maxn];
ll sum[maxn];

int main(){ 
    IO;cout.precision(10);cout<<fixed;  
    int n,m;cin>>n>>m;
    for1(i,m) cin>>a[i];
    for1(i,m-1){
        int x = min(a[i],a[i+1]),y = max(a[i],a[i+1]);
        if(x==y) continue;
        sum[1]+=y-x;
        sum[x]-=y-x;
        sum[x]+=y-1;
        sum[x+1]-=y-1;
        sum[x+1]+=y-x-1;
        sum[y]-=y-x-1;
        sum[y]+=x;
        sum[y+1]-=x;
        sum[y+1]+=y-x;
    }  
    for1(i,n){
        sum[i] = sum[i]+sum[i-1];
        cout<<sum[i]<<' ';
    }
    return 0;
}

F.
題意:
F題意是1e6長度的字符串,你可以進行一次操作,操作可以選擇一段區間反轉字符串。你的目的是儘可能找到一段最長區間,使得區間內每一個字母都只出現一次。輸出這個區間的最大長度。
思路:
問題等價於找到兩個完美區間,且這兩個區間任取字符不同,且總字符數最大。
轉換成這個問題之後就可以dp+二進制了。
代碼:

#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)
const int inf = 2e9+5;
const ll INF = 2e18+5;

int a[1<<20];

int main(){
    IO;cout.precision(10);cout<<fixed;  
    string s;cin>>s;
    int n = s.size();
    forn(i,n) s[i]-='a';
    forn(i,n){
        int num = 0;
        for(int j = i;j<n;j++){
            if(num&(1<<s[j])) break;
            num|=(1<<s[j]);
            a[num] = __builtin_popcount(num);
        }
    }
    forn(j,1<<20){
        forn(i,20)if(j&(1<<i)){
            a[j] = max(a[j],a[j^(1<<i)]);
        }
    }
    int ans = 0;
    forn(i,1<<20) ans = max(ans,a[i]+a[(1<<20)-1-i]);
    cout << ans <<'\n';
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章