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;
} 
posted @ 2021-06-15 15:06  0xYuk1  阅读(116)  评论(0)    收藏  举报