1. 程式人生 > 其它 >Codeforces Round #725 (Div. 3) 題解

Codeforces Round #725 (Div. 3) 題解

Codeforces Round #725 (Div. 3)

比賽連結:https://codeforces.com/contest/1538

A. Stone Game

題意:對一個排列,左右開取,問最少取多少個可以取走最大權值的石頭和最小權值的石頭

題解:全左,全右,左右共三種取法,做比取最小的一個就好

程式碼實現:

#include <bits/stdc++.h>
using namespace std;
int main(){
	int t; cin >> t;
	while(t--){
		int n, ans = 0;
		cin >> n;
		int mxidx = -1,miidx = -1;
		for(int i = 1;i <= n;i++){
			cin >> a[i];
			if(a[i] == 1){
				miidx = i;
			}else if(a[i] == n){
				mxidx = i;
			}
		}
		if(miidx > mxidx) swap(miidx,mxidx);
		ans = mxidx;
		ans = min(ans,n - miidx+1);
		ans = min(ans,miidx+(n - mxidx + 1));
		cout << ans << endl;
	}
	return 0;
} 

B. Friends and Candies

題意:小朋友有糖,使所有小朋友有一樣個數的糖,可以從一部分小朋友中拿糖出來分問最少運算元

題解:大於平均的拿出來分就好

程式碼實現:

#include <bits/stdc++.h>
using namespace std;
signed main(){
	int t;cin >> t;
	while(t--){
		int n, tmp, sum = 0, ans= 0;
		cin >> n;
		for(int i = 1;i <= n;i++){
			cin >> tmp;
			sum += tmp;
		}
		if(sum % n != 0){
			cout << "-1\n";//不可整除當然無法平均分
			continue;
		}
		sum /= n;
		for(int i=1;i<=n;i++){
			if(a[i] > sum) ans++;
		}
		cout << ans << endl;
	}
	return 0;
} 

C. Number of Pairs

題意:給定一個n大小的陣列,問有多少個pair(i,j)滿足ai + aj 在給定的l,r之間

題解:排序後二分

程式碼實現:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 10;
int vc[maxn];
int vc[maxn];
signed main(){
	int t;cin >> t;
	while(t--){
		int n,l,r,tmp;
		cin >> n >> l >> r;
		int ans = 0;
		for(int i = 1;i<=n;i++){
			cin >> vc[i];
		}
		sort(vc + 1,vc + n + 1);
		for(int i = 1;i<=n;i++){
			if(vc[i] > r) break;
			int lbound = vc[i] < l ? l - vc[i] : 0;
			int rbound = r - vc[i];
			int lidx = lower_bound(vc + 1,vc + n + 1,lbound) - vc;
			int ridx = upper_bound(vc + 1,vc + n + 1,rbound) - vc;
			if(lidx <= i) lidx = i + 1;
			if(lidx <= ridx)ans += ridx - lidx; 
		}
		cout << ans << endl;
	}
	return 0;
} 

D. Another Problem About Dividing Numbers

題意:兩個數,可以從中提取因子,問能否經過k次操作使兩數相同

題解:

ver1(當時思路):列印素數表,兩數分解質因數,算出共有因子數和不同因子數,以及是否不同因子在同一數字上,最後求解。

ver2(賽後思路):不列印素數表,在分解因子的時候跳一點除了2其他質數都是奇數,但是否不同因子在同一數字上可以通過兩數是否為倍數關係進行判斷

ver1程式碼實現:

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) 
using namespace std;
const int maxn = 3e5+10;
const int mxx = 100010;
const int INF = 1e18;
typedef long long LL;
bool prime[mxx];
int rec[mxx], cnt;
void init_prime(){
    cnt = 0;
    memset(prime, true, sizeof(prime));
    prime[0] = prime[1] = false;///表明true為質數
    for (int i = 2; i <= mxx; ++i){
        if (prime[i]) rec[cnt++] = i;
        //此處邊界判斷為rec[j] <= maxn / i,如果寫成i * rec[j] <= maxn,需要確保i * rec[j]不會溢位int
        for (int j = 0; j < cnt && rec[j] <= mxx / i; ++j){
            prime[i * rec[j]] = false;
            if (i % rec[j] == 0)
                break;
        }
    }
}
map<int,int> mpa,mpb;
signed main(){
	fio;
	init_prime();
	int t;
	cin >> t;
	while(t--){
		int a,b,k;
		cin >> a >> b >> k;
		mpa.clear();mpb.clear(); 
		int eq = 0,dif = 0;
		for(int i = 0;i < cnt;i++){
			while(a % rec[i] == 0){
				mpa[rec[i]]++;
				a /= rec[i];
			}
		}
		if(a != 1)mpa[a]++;
		for(int i = 0;i < cnt;i++){
			while(b % rec[i] == 0){
				mpb[rec[i]]++;
				b /= rec[i];
			}
		}
		if(b != 1)mpb[b]++;
		int f1 = 0,f2 = 0;
		for(auto t:mpa){
			int num = t.first;
			eq += min(mpa[num],mpb[num]);
			dif += abs(mpa[num] - mpb[num]);
			if(mpa[num] > mpb[num])f1 = 1;
			else if(mpa[num] < mpb[num])f2 = 1;
			mpa[num] = mpb[num] = 0;
		}
		
		for(auto t:mpb){
			int num = t.first;
			eq += min(mpa[num],mpb[num]);
			dif += abs(mpa[num] - mpb[num]);
			if(mpb[num] > mpa[num])f2 = 1;
			else if(mpa[num] > mpb[num])f1 = 1;
			mpa[num] = mpb[num] = 0;
		}
		int mstep = 0;
		if(dif == 0)mstep = 2;
		else mstep = f1 + f2;
		int sum = dif + eq * 2;
		if(k >= mstep && k <= sum){
			printf("YES\n");
		} 
		else printf("NO\n");
	}
	return 0;
} 

ver2程式碼實現:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL) 
int find(int n){
    int ans = 0;
    while(n % 2 == 0){
        n = n/2;
        ans++;
    }
    for(int i = 3;i*i<=n;i+=2){
        while(n%i == 0){
            n = n/i;
            ans++;
        }
    }
    if(n > 1)ans++;
    return ans;
}
void solve(){
	int a, b, k;
        cin >> a >> b >> k;
        int cnt = find(a);
		cnt +=  find(b);
		if(k == 1){
            if(a == b || ((a%b!=0 && b%a!=0))){
                cout<<"NO"<<endl;
                return ;
            }
    	}
        if(k > cnt){
            cout << "NO" <<endl;
            return ;
        }
    	cout<<"YES"<<endl;
}
int32_t main(){
    fio;
    int t;
    cin >> t;
    while(t--){
        solve();
    }
}

E. Funny Substrings (補題)

題意:給一些符號賦值,然後進行加減操作,問最後一個符號中出現了多少個"haha"

題解:從長度入手,如果知道一個字串首尾的3個字母,pair儲存首尾字元以及"haha"個數即可

程式碼實現:

#include <bits/stdc++.h>
using namespace std;
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL) 
typedef long long LL;
LL find(string s){
    LL cnt = 0;
    for(LL i = 0;i + 4 <= s.size();i++){
        cnt += (s.substr(i,4) == "haha");
    }
    return cnt;
}
auto merge(pair<LL,string> a,pair<LL,string> b){
    LL cnt = a.first + b.first;
    string s = a.second + b.second;
    for (LL i = max(0, int(a.second.size()) - 3); i + 4 <= s.size() && i < int(a.second.size()); i++) {
        cnt += "haha" == s.substr(i, 4);
    }
     if (s.size() >= 6) {
        s.erase(s.begin() + 3, s.end() - 3);
    }
    return make_pair(cnt,s);
}
int main(){
    fio;
    LL t;
    cin >> t;
    while(t--){
        map<string,pair<LL,string>> mp;
        string last;
        LL n;
        cin >> n;
        while(n--){
            string a,op,b,c;
            cin >> a >> op;
            if(op == ":="){
                cin >> b;
                mp[a] = {find(b),b};
            }else{
                cin >> b >> op >> c;
                mp[a] = merge(mp[b],mp[c]);
            }
            last = a;
        }
        cout << mp[last].first << "\n";
    }
    
}

F. Interesting Function

題意:從l到r變了幾個數字

題解:滾一下就好

程式碼實現:

#include <bits/stdc++.h>
using namespace std;
signed main(){
	int t,l,r;
	cin >> t;
	while(t--){
		cin >> l >> r;
	    int ans = 0;
	    for (int i = 1; i <= 10; i++){
	        ans += r - l;
	        l /= 10, r /= 10;
	    }
	    cout << ans << "\n";
	}
	return 0;
} 

G. Gift Set(補題)

題意:紅球和藍球各有x個和y個,給定a,b,從其中一個拿a個,另外一個拿b個問最多可以拿多少次

題解:如果a,b相等那麼答案是其中的較小值去除a,如果不相等,a賦較大值,然後二分答案(總次數具有單調性,故考慮對其二分答案)

若是k則有

a × k + b × (n−k) ≤ x

b × k + a × (n−k) ≤ y

如果a > b那麼

k ≤ (x - b * n) / ( a - b)

(y - a*n) / (b-a) ≤ k

此外還需要滿足的條件有 0 ≤ k ≤ n

知道這些後就可以求解答案了

解題程式碼:

#include <bits/stdc++.h>
using namespace std;
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL) 
#define endl '\n'
signed main(){
	fio;
	int t;cin >> t;
	while(t--){
		int x,y,a,b;
		cin >>x >> y >>a >>b;
		if(a == b){
			cout << min(x,y)/a << endl;
			continue;
		}
		if(a < b)swap(a,b);
		int l = 0, r = (x + y)/(a + b);
		while(l < r){
			int mid = (l + r + 1)/2;
			int qua1 = max(0, (a * mid - y + a - b - 1) / (a - b));
			int qua2 = min(mid, (x - b * mid + a - b) / (a - b) - 1);
			if(qua1 <= qua2){
				l = mid;
			}else{
				r = mid - 1;
			}
		}
		cout << l << endl;
	}
	return 0;
}