Codeforces Round 725 (Div. 3)
A.Stone Game
题意
给出一个长度为n n n 的序列,每次可进行一次操作,求达成目标的最小操作数。
操作:每次可以删除序列的头元素或尾元素。
目标:最小值以及最大值被删除。
思路
枚举三种可行的操作,取最小值。
1、从序列头开始删,删到需要删除的数停止。然后从序列尾开始删,删到需要删除的数停止。
2、从序列头开始删,直至删除两个需要删除的数。
3、从序列尾开始删,直至删除两个需要删除的数。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> #include <algorithm> #include <map> #include <set> #include <cstring> #include <cmath> using namespace std;int n;const int N = 10010 ;int a[N];int main () { int t; cin >> t; while (t--){ int maxc = -1 ,minc = 110 ; cin >> n; int p,q; for (int i = 0 ; i < n; i++) cin >> a[i]; for (int i = 0 ; i< n; i ++){ if (minc > a[i]) minc = a[i], p = i; if (maxc < a[i]) maxc = a[i], q= i; } if (p > q) swap (p,q); int cnt = 0 ,idx = 0 ,ans = 0 ; ans = min (p + 1 , n - p)+min (n - q, q + 1 ); cnt = q + 1 ; idx = n - p; ans = min (ans,cnt); ans = min (ans,idx); cout << ans << '\n' ; } return 0 ; }
B. Friends and Candies
题意:
共有n n n 个人,每个人有数量为a [ i ] a[i] a [ i ] 的物品,求使所有人物品数量相同的最小操作数。
操作:拿出一个人的东西分给其他人。
思路:
a [ i ] a[i] a [ i ] 大于平均值的,对答案的贡献为1 1 1
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <iostream> #include <algorithm> #include <map> #include <set> #include <cstring> #include <cmath> using namespace std;int n;const int N = 2e5 + 7 ;int a[N];int main () { int t; cin >> t; while (t--){ cin >> n; long long sum = 0 ; for (int i = 0 ; i < n; i++) cin >> a[i],sum += a[i]; if (sum % n != 0 ){ puts ("-1" );continue ; }else { long long cnt = sum / n; int idx = 0 ; for (int i = 0 ; i< n; i++){ if (a[i] > cnt ) idx++; } cout << idx << '\n' ; } } return 0 ; }
C. Number of Pairs
题意:
给出一个数组a a a 以及一个区间[ l , r ] [l,r] [ l , r ] ,求满足l < = a [ i ] + a [ j ] < = r l<=a[i]+a[j]<=r l <= a [ i ] + a [ j ] <= r 的数对p a i r ( i , j ) pair(i,j) p ai r ( i , j ) 的数量
思路:
这题的i , j i,j i , j 顺序其实没什么关系,可以直接排序。
二分找边界。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> #include <algorithm> #include <map> #include <set> #include <cstring> #include <cmath> using namespace std;int n;const int N = 2e5 + 7 ;int a[N];int main () { int t; cin >> t; while (t--){int l,r; cin >> n >>l >> r; for (int i = 0 ; i < n; i++) cin >> a[i]; sort (a,a+n); long long ans = 0 ; for (int i =0 ; i< n; i ++){ int x = lower_bound (a,a+n,l-a[i])-a; int y = upper_bound (a,a+n,r-a[i])-a; if (x <= i) x = i +1 ; if (y <= i) y = i + 1 ; ans += (y - x); } cout << ans << '\n' ; } return 0 ; }
D. Another Problem About Dividing Numbers
题意:
给出两个整数a a a 和b b b ,每次可以进行一次操作,将a除上一个数c c c ,或者将b除上一个数c c c ,c c c 能够整除a a a 或者b b b ,并且c c c 大于1。问是否能通过恰好k k k 次操作使得a a a 和b b b 相等。
思路:
讨论出使得a a a 和b b b 相等所需要的最小次数M i n c n t Mincnt M in c n t ,以及所需要的最大次数M a x c n t Maxcnt M a x c n t 。
最小次数:
如果a = b a=b a = b ,不需要进行操作,M i n c n t = 0 Mincnt=0 M in c n t = 0 ;
如果a ∣ b a|b a ∣ b 或者b ∣ a b|a b ∣ a ,我们可以通过一次操作使得a = b a=b a = b ,M i n c n t = 1 Mincnt =1 M in c n t = 1 ;
如果以上两种情况都不满足,则需要两次操作,即二者都除上他们本身,M i n c n t = 2 Mincnt = 2 M in c n t = 2 。
最大次数:
分解质因数,使a a a 和b b b 变成1的操作次数即最大次数
因为只需最小次数M i n c n t Mincnt M in c n t 就能使a = b a=b a = b ,其他k − M i n c n t k-Mincnt k − M in c n t 次无论怎么操作,都能符合题意。
所以如果给出的k k k 在M i n c n t − − M a x c n t Mincnt--Maxcnt M in c n t − − M a x c n t 之间,k k k 就一定能满足题目要求。
需要注意当k = 1 k=1 k = 1 时,这意味着我们只能对其中一个数进行一次操作,需要保证a ∣ b a|b a ∣ b 或者b ∣ a b|a b ∣ a ,即M i n c n t = 1 Mincnt=1 M in c n t = 1 。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <iostream> #include <algorithm> #include <cstring> #include <cmath> using namespace std;int n;const int N = 2e5 + 7 ;int prime[N],v[N],m;void getprime (int n) { for (int i = 2 ; i <= n; i ++){ if (!v[i]) { prime[++m] = i; v[i] = i; } for (int j = 1 ; j <= m; j ++){ if (prime[j] > v[i] || prime[j] > n / i) break ; v[i*prime[j]] = prime[j]; } } } int f (int n) { int cnt = 0 ; for (int i = 1 ; i <= m; i ++){ while (n % prime[i] == 0 ){ n /= prime[i]; cnt++; } if (n == 1 ) break ; if (n < prime[i]) break ; } if (n > 1 ) cnt++; return cnt; } int main () { int t; cin >> t; int M = sqrt (1e9 ); getprime (M); while (t--){ int x,y,k, Mincnt,Maxcnt; cin >> x >> y >> k; if (x > y) swap (x,y); int gcd = __gcd(x,y); if (gcd == x && x != y) Mincnt = 1 ; else if (x == y) Mincnt = 0 ; else Mincnt = 2 ; Maxcnt = f (x) + f (y); if (Mincnt <= k && k <= Maxcnt && (k != 1 || k == 1 && Mincnt == 1 ) ) puts ("YES" ); else puts ("NO" ); } return 0 ; }
F. Interesting Function
题意:
给出一个初始数l l l ,和终点数r r r 。l l l 自增到r r r ,求各位数字变化了多少次。
比如1 —— 4 1——4 1——4 ,变化了三次,个位三次( 1 − > 2 − > 3 − > 4 ) (1->2->3->4) ( 1 − > 2 − > 3 − > 4 ) ;
8 —— 12 8——12 8——12 ,变化了六次,个位五次( 8 − > 9 − > 0 − > 1 − > 2 ) (8->9->0->1->2) ( 8 − > 9 − > 0 − > 1 − > 2 ) ,十位一次( 0 − > 1 ) (0->1) ( 0 − > 1 ) 。
思路:
先计算出除了进位的各位数字的变化,不难发现除了进位的变化就是这个数字本身(从0开始)。
观察进位的变化,对于十位上的数来说,每加上10 10 10 ,对答案的贡献就加一,只需要计算出加了多少个10 10 10 即可,其他位数同理。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> using namespace std;int main () { int t,L,R; cin >> t; while (t--){ cin >> L >> R; int idx = R ,cnt = L; while (R){ R /= 10 ; idx += R; } while (L){ L /= 10 ; cnt += L; } cout << idx - cnt << '\n' ; } }
G. Gift Set
题意:
有x x x 个红糖果和y y y 个蓝糖果,将这些糖果按固定的分配方案分组。要求:每组包含a a a 个红糖果,b b b 个蓝糖果;或者a a a 个蓝糖果,b b b 个红糖果。输出能分的最大组数。
思路:
二分答案要分的组数n n n 。
其中一组为k k k ,另外一组为n − k n-k n − k 。
x , y , k x,y,k x , y , k 需满足以下条件
{ x < = a ∗ k + b ∗ ( n − k ) y < = a ∗ ( n − k ) + b ∗ k 0 < = k < = n \begin{cases}
x <= a*k+b*(n-k)\\
y <= a*(n-k)+b*k\\
0 <= k <=n
\end{cases}
⎩ ⎨ ⎧ x <= a ∗ k + b ∗ ( n − k ) y <= a ∗ ( n − k ) + b ∗ k 0 <= k <= n
整理得:
{ k > = ( y − n ∗ a ) / ( b − a ) k < = ( n ∗ b − x ) / ( b − a ) k > = 0 k < = n \begin{cases}
k >= (y-n*a)/(b-a)\\
k<= (n*b - x)/(b-a)\\
k >= 0\\
k <= n
\end{cases}
⎩ ⎨ ⎧ k >= ( y − n ∗ a ) / ( b − a ) k <= ( n ∗ b − x ) / ( b − a ) k >= 0 k <= n
二分检查是否满足上式即可。
另外如果a = = b a==b a == b ,可以直接得出答案。
注意二分模板的使用,以及区间左端点向上取整,右端点向下取整。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> #include <algorithm> #include <cstring> #include <cmath> using namespace std;typedef long long ll;ll a,b,x,y; bool check (ll n) { ll l2 = ceill ((y - n*a)*1.0 /(b-a)), r2 = floorl ((b*n -x )*1.0 / (b-a)); l2 = max (0ll ,l2), r2 = min ( n, r2); return l2 <= r2; } int main () { int t; cin >> t; while (t--){ cin >> x >>y >> a >> b; if (a < b) swap (a,b); if (a == b) { cout << min (x,y) / a << '\n' ;continue ; } else { ll l = 0 ,r = 1e9 + 7 ; while (l < r) { ll mid = l + r +1 >> 1 ; if (check (mid)) l = mid; else r = mid - 1 ; } cout << l << '\n' ; } } }