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