1. 程式人生 > 實用技巧 >.Net 異常最佳做法

.Net 異常最佳做法

Codeforces Round #661 (Div. 3)

原作者為 DOEMsy@cnblogs, 本作品採用 CC 4.0 BY 進行許可,轉載請註明出處。

上分場找回了點自信。

https://codeforces.com/contest/1399

A. Remove Smallest

題意

給定一個數組 \(a_1,a_2,...,a_n\) ,每次操作可以選取陣列中兩個相差不大於 \(1\) 的數字,刪除其中一個。

詢問能否刪到最後剩餘一個數字。

解題

保證陣列有序後,相鄰元素差值不超過 \(1\) 即可。

#include<bits/stdc++.h>
//#include<windows.h>
#define ll long long
#define fr(i,n) for(ll i=0;i<n;i++)

using namespace std;

int main(){

    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        int a[55];
        fr(i,n) cin>>a[i];
        sort(a,a+n);
        int p = 1;
        fr(i,n-1){
            if(a[i+1]-a[i]>1)   p++;
        }
        //cout<<1<<endl;
        if(p>1)    cout<<"NO"<<endl;
        else        cout<<"YES"<<endl;
    }

    return 0;
}
 

B. Gifts Fixing

題意

\(n\) 個禮物,每個禮物由 \(a_i\) 個糖果和 \(b_i\) 個橘子組成。

每次可以對一個禮物進行以下操作:

  • 吃掉一個糖果;
  • 吃掉一個橘子;
  • 吃掉一個糖果和一個橘子。

詢問最少多少次操作可以使得所有禮物的糖果和橘子都相同。

解題

簡單貪心,將所有的糖果和橘子變成分別變成最少的數量,每一堆的最少花費為 \(max(a_i-a_{min},b_i-b_{min})\) ,求和即可。

#include<bits/stdc++.h>
//#include<windows.h>
#define ll long long
#define fr(i,n) for(ll i=0;i<n;i++)

using namespace std;

int main(){

    int t;cin>>t;
    while(t--){
        ll a[55],b[55];
        int n;cin>>n;
        fr(i,n) cin>>a[i];
        fr(i,n) cin>>b[i];
        ll mina = *min_element(a,a+n);
        ll minb = *min_element(b,b+n);
        ll ans = 0;
        fr(i,n){
            ans+=max(a[i]-mina,b[i]-minb);
        }
        cout<<ans<<endl;
    }

    return 0;
}
 

C. Boats Competition

題面

有一群人,戰鬥力為 \(w_1,w_2,...,w_n\) ,要求兩兩組隊,且每個隊伍的戰鬥力必須相同。

詢問最多可以組成多少個隊伍。

解題

由於人數和戰鬥力範圍較小,可以直接在 \([2,2n]\) 內遍歷隊伍戰鬥力範圍,取組成數量最多值,複雜度 \(O(2n^2)\)

#include<bits/stdc++.h>
//#include<windows.h>
#define ll long long
#define fr(i,n) for(ll i=0;i<n;i++)
#define memset0(dp) memset(dp,0,sizeof(dp))

using namespace std;

int main(){
    
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        int a[550];memset0(a);
        fr(i,n){
            int inp;cin>>inp;
            a[inp]++;
        }
        int  maxs = 0,maxnum = 0;
        frr(s,2,2*n+1){
            int num = 0;
            frr(i,1,n+1){
                if(s-i>0)   num+=min(a[i],a[s-i]);
            }
            num/=2;
            maxnum = max(num,maxnum);
        }
        cout<<maxnum<<endl;
    }
    return 0;
}
 

D. Binary String To Subsequences

題意

給定一個由 \(01\) 組成的字串 \(S\),問最少分成多少個子串,使得每個子串 \(01\) 交錯。

並且輸出每一個字元被分配到的子串編號。

解題

注意題中說的是子串,不是連續子串。

類似 \(dp\) 的思路,將前面的所有子串狀態儲存,對於當前字元 \(S_i\) 有:

  • 如果存在結尾與 \(S_i\) 不同的子串,則可以用 \(S_i\) 續接該子串。
  • 否者用 \(S_i\) 新建一個子串。

關於子串的儲存只需要記錄結尾和編號即可,複雜度 \(O(n)\)

#include<bits/stdc++.h>
//#include<windows.h>
#define ll long long

#define fr(i,n) for(ll i=0;i<n;i++)
#define frs(i,n,flag)   for(ll i=0;i<n&&flag;i++)
#define e5 100005
#define print_arr(begin,end)    for(auto it = begin;it!=end;it++)  cout<<*it<<" "; cout<<endl;

using namespace std;
int a[2*e5];
int main(){
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        string inp;cin>>inp;
        int maxsz = 0;
        //fr(i,n) a[i] = 0;
        stack<int>ct[2];
        fr(i,n){
            if(!ct[!(inp[i]-'0')].empty()){
                a[i] = ct[!(inp[i]-'0')].top();
                ct[!(inp[i]-'0')].pop();
                ct[(inp[i]-'0')].push(a[i]);
            }else{
                ct[(inp[i]-'0')].push(++maxsz);
                a[i] = maxsz;
            }
        }
        cout<<maxsz<<endl;
        print_arr(a,a+n);

    }

    return 0;
}

E1. Weights Division (easy version)

題意

給定一棵帶邊權的樹,每次操作可以選擇一條邊,使其權值 \(w_i = \lfloor\frac{w_i}{2}\rfloor\)

詢問至少多少次操作,可以使得葉節點到根部的路徑權總和小於等於 \(S\)

解題

貪心,選取一個邊會對權值和產生的影響為 \((w_i-\lfloor\frac{w_i}{2}\rfloor)*cnt\)\(cnt\) 為經過該邊的葉節點數量,優先選取影響大的。

\(dfs\) 跑出每一條邊的 \(w_i,cnt\),再以單調佇列維護,不斷操作,直到和小於等於 \(S\)

複雜度 \(O(nlogn)\)

#include<bits/stdc++.h> 
//#include<windows.h>
#define ll long long

#define fr(i,n) for(ll i=0;i<n;i++)
#define frs(i,n,flag)   for(ll i=0;i<n&&flag;i++)

#define frr(i,j,n) for(ll i=j;i<n;i++)
#define r_frr(i,j,n) for(ll i=n-1;i>=j;i--)

#define frrs(i,j,n,flag)    for(ll i=j;i<n&&flag;i++)
#define r_frrs(i,j,n,flag)    for(ll i=n-1;i>=j&&flag;i--)


#define yes "yes"
#define no  "no"

#define memset0(dp) memset(dp,0,sizeof(dp))
#define min_get(a,b) a = min(a,b)
#define max_get(a,b) a = max(a,b)
#define PI  3.14159265354

#define print_arr(begin,end)    for(auto it = begin;it!=end;it++)  cout<<*it<<" "; cout<<endl;
#define log_this(name,value)    cout<<name<<": "<<value<<endl;

#define e5 100005
#define e6 1000006

using namespace std;
ll     to_ll(string s)    {stringstream ss;ss<<s<<endl;ll a;ss>>a;return a;}
string  to_str(double a)    {stringstream ss;ss<<a<<endl;return ss.str();}
template<class T>inline void read(T &x){T f=1;x=0;char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}x*=f;}

map<int,ll>eg[1*e5];

struct cst_cnt{
    ll cst,cnt;
    cst_cnt(ll cs,ll cn){cst = cs,cnt = cn;}

    bool operator < (const cst_cnt o)const{
        return (cst-cst/2)*cnt<(o.cst-o.cst/2)*o.cnt;
    }
};

priority_queue<cst_cnt>cost;

ll sum;

ll dfs(int i,int last){
    ll cst;
    if(i==last) cst = 0;
    else cst = eg[i][last];
    ll cnt = 0;
    if(eg[i].size()==1&&i!=last) cnt = 1;
    else{
        for(auto it:eg[i]){
            if(it.first!=last){
                cnt += dfs(it.first,i);
            }
        }
    }
    sum += cnt*cst;
    cost.push(cst_cnt(cst,cnt));
    return cnt;
}

int main(){

    int t;cin>>t;
    while(t--){
        ll n,s;cin>>n>>s;
        frr(i,1,n+1) eg[i].clear();
        ll v,u,w;
        #define p(a,b) pair<int,ll>(a,b)
        fr(i,n-1){
            cin>>v>>u>>w;
            eg[v].insert(p(u,w));
            eg[u].insert(p(v,w));
        }
        while(!cost.empty()) cost.pop();
        sum = 0;
        dfs(1,1);

        ll ans = 0;
        while(sum>s){
            cst_cnt tmp = cost.top();
            sum -= (tmp.cst-tmp.cst/2)*tmp.cnt;
            tmp.cst/=2;
            cost.pop();
            cost.push(tmp);
            ans++;
        }
        cout<<ans<<endl;
    }
    return 0;
}