Codeforces Round #653 (Div. 3)(A, B, C, D)

A. Required Remainder

A. Required Remainder
题意:给出 x , y , n x, y, n x,y,n,求一个最大的 k ∈ [ 1 , n ] k\in[1, n] k[1,n]使 k % x = y k\%x = y k%x=y

思路:已知 k = u ∗ x + y k = u*x + y k=ux+y u u u为未知。我们是在区间 [ 1 , n ] [1, n] [1,n]之间取 k k k,我们可以得到在区间 [ 1 , n ] [1, n] [1,n] x x x的最大倍数 n / x ∗ x ^n/_x*x n/xx,如果 n / x ∗ x + y > n ^n/_x*x+y > n n/xx+y>n,那 k = n / x ∗ x − x + y k = ^n/_x*x-x+y k=n/xxx+y,如果 n / x ∗ x + y < = n ^n/_x*x+y <= n n/xx+y<=n,那 k = n / x ∗ x + y k = ^n/_x*x+y k=n/xx+y
代码:

#include<bits/stdc++.h>
using namespace std;
int main() {
    
    
	int t;
	cin >> t;
	while(t--) {
    
    
		int x, y, n, m;
		cin >> x >> y >> n;
		m = n / x * x;//x在区间的最大倍数。
		if(m + y > n) cout << m + y - x << endl;
		else cout << m + y << endl;
		
	}
	return 0;
} 

B. Multiply by 2, divide by 6

B. Multiply by 2, divide by 6
题意:给出一个数n,对数有两种操作 n ∗ = 2 n *= 2 n=2 n / = 6 n /= 6 n/=6,问是否可以在若干次操作后使 n = 1 n=1 n=1,如果可以求最小操作次数,如果不行输出-1。

思路:要使 n n n最后变成1,只有在n = 6的时候 n / = 6 n/=6 n/=6才行,所以我们要检验 n = 3 x ∗ 2 y n = 3^x*2^y n=3x2y x > = y x >= y x>=y,如果 x < y x < y x<y那到最后一定会有2的倍数余下。

代码:

#include<bits/stdc++.h>
using namespace std;
int come(int *m) {
    
    //求3^x,中的x。
	int ans = 0;
	while(*m) {
    
    
		if(*m % 3 == 0)  ans++;
		else break;
		*m /= 3;
	}
	return ans;
}

int check(int n) {
    
    //确定n/(3^x)是2的倍数,并且返回2^y中的y
	for(int i=0; i<32; i++) {
    
    
		if(n == 1<<i) return i;
	}
	return -1;
}
int main() {
    
    
	int t;
	cin >> t;
	while(t--) {
    
    
		int n, m, x;
		cin >> n;
		if(n == 1) {
    
    //特判
			cout << 0 << endl;
			continue;
		}
		if(n % 3 == 0) {
    
    
			m = come(&n);
			x = check(n);
			if(x > m || x == -1) cout << -1 << endl;
			else cout << m+(m-x) << endl;
		} 
		else cout << -1 << endl;
	}
	return 0;
} 

C. Move Brackets

C. Move Brackets
题意:给出一串由 ′ ( ′ , ′ ) ′ '(',')' ()组成的字符串,可以将其中任意一个字符移到字符串开头或结尾,求最小移动次数,使每个左括号’(’,可以和右括号’)'匹配:类似于 ( ( ) ) , ( ) ( ) (()),()() (()),()()

思路:每个可以先去掉可以匹配的括号“()”,再将剩下的类似于"))))(((("的字符串再移动,我们只需要将所有右括号移到右边就完成了匹配,也就是字符串长度的一半。

代码:

#include<bits/stdc++.h>
using namespace std;
char s[55];
int main() {
    
    
	int t;
	cin >> t;
	while(t--) {
    
    
		stack<char> S;
		int n;
		cin >> n >> s;
//		cout << n << s;
		for(int i=0; s[i]; i++) {
    
    
			if(S.empty() || S.top() == ')' || (S.top() == '(' && s[i] == '(')) {
    
    
				S.push(s[i]);
			}
			else {
    
    
				S.pop();
			}
		}
		cout << S.size()/2 << endl;
	}
	return 0;
} 

D. Zero Remainder Array

D. Zero Remainder Array
题意:给出一个含 n n n个元素的序列 a a a,和一个数字 k k k。有一个数 x x x,有两种操作:1. a i + x , x + + a_i+x,x++ ai+xx++,2 . x + + .x++ .x++。问最少操作数使a中的每个元素都是k的倍数。

思路:我们按 k − ( a i % k ) k-(a_i\%k) k(ai%k)的大小进行排序。小的排在前面,优先加上 x x x使 a i a_i ai成为 k k k的倍数。但是在这种情况下可能会出现有相同的 k − ( a i % k ) k-(a_i\%k) k(ai%k)出现,所以我们必须将 k − ( a i % k ) k-(a_i\%k) k(ai%k)加k,使他们不相等且依然是k的倍数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
ll s[N];
map<ll, ll> M;//map标记同一个k-(a_i\%k)出现次数,对应加上多少倍的k。
int main() {
    
    
	ll t;
	cin >> t;
	while(t--) {
    
    
		M.clear();
		ll n, k, m, ans = 0, x = 0;
		cin >> n >> k;
		for(int i=0; i<n; i++) {
    
    
			scanf("%lld", &s[i]);
			m = k - (s[i] % k);
			if(m == k) s[i] = 0;
			else {
    
    
				s[i] = m+M[m]*k;//计算k-(a_i\%k)。
				M[m]++;//出现次数。
			}
		}
		sort(s, s+n);//排序。
		for(int i=0; i<n; i++) {
    
    //计算结果。
			if(s[i] != 0) {
    
    
				ans += s[i] - x + 1;
				x = s[i] + 1;
			}
		}
		cout << ans << endl;
	}
	return 0;
} 

一个总结:x的每次操作都会加1,所以最终x的值就是操作次数,我们求出最大的 k − ( a i % k ) k-(a_i\%k) k(ai%k),x一定会在最后达到这个数字,所以(这个数字+1)就是结果。
优化代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
ll s[N];
map<ll, ll> M;//map标记同一个k-(a_i\%k)出现次数,对应加上多少倍的k。
int main() {
    
    
	ll t;
	cin >> t;
	while(t--) {
    
    
		M.clear();
		ll n, k, m, ans = 0, x = 0;
		cin >> n >> k;
		for(int i=0; i<n; i++) {
    
    
			scanf("%lld", &s[i]);
			m = k - (s[i] % k);
			if(m == k) s[i] = 0;
			else {
    
    
				s[i] = m+M[m]*k;//计算k-(a_i\%k)。
				M[m]++;//出现次数。
			}
			ans = max(ans, s[i]);
		}
		ans != 0 ? cout << ans+1 << endl : cout << 0 << endl;
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_45363113/article/details/107016675