2020-05-18 — 习题训练一题解
A.Phoenix and Balance
题意:给一组数2^1,2^2,……,2^n,然后平均分为两组,使其两组和的差绝对值最小
注意到2 ^ (n+1) = 2^0 + ... 2 ^n +1;
所以 a[n] = a[0] + .. a[n-1] + 2;
含a[n]的一方尽可能选小的就可
#include <iostream> #include <cstdio> using namespace std; int n, a[32]; int q_pow(int n) { int a = 2, res = 1; while(n) { if(n & 1) res *= a; a *= a; n >>= 1; } return res; } int t; int main() { cin >> t; a[1] = 2; for(int i = 2;i <= 30; ++ i) a[i] = 2 * a[i-1]; while(t--) { int res = 0; cin >> n; res = a[n]; int num = 1; for(int i = 1;i <= n; ++ i) { if(num == n/2){ for(int j = i;j <= n-1; ++ j) res -= a[j]; break; } else{ res += a[i]; num ++; } } cout << res << endl; } // a[n] = a[1] + ... a[n-1] - 1; // a[n] + a[1] + ... a[m] = }
B.Phoenix and Beauty
题意:给出n个数,通过进行增加新的数字(数字必须在1-n之间)使得数列周期为k, 并输出长度, 若弄不了,输出-1
当 k < n个数中不同的数时,输出-1吧,return 0;
扫一遍数组,遇到数就把所有的数都输出一遍,不够k个数随便添个数,凑够k个数,周期就是k了,长度不会超给定的范围
#include <iostream> #include <cstring> #include <algorithm> #include <set> using namespace std; int n, a[6666], k, t, b[6666]; int main() { cin >> t; while(t--) { memset(b, 0, sizeof(0)); cin >> n >> k; int cnt = 0; for(int i = 1;i <= n; ++ i) { cin >> a[i]; int flag = 1; for(int j = 1;j <= cnt; ++ j) if(b[j] == a[i]) flag = 0; if(flag) b[++cnt] = a[i]; } sort(b + 1, b + 1 + cnt); if(k < cnt){ cout << "-1" << endl; continue; } cout << n * k << endl; for(int i = 1;i <= n; ++ i) { for(int j = 1;j <= cnt; ++ j) cout << b[j] << " "; int j = k - cnt; while(j) { cout << b[cnt] << " "; j --; } } cout << endl; } }
C.Road To Zero
题意:有两个数x,y,其中一个数增1或减1的话,需要花费a元,如果两个数一起减1或加1的话,需要花费b元,询问xy都变为0时花费的最少钱
分情况讨论
#include <iostream> using namespace std; typedef long long LL; LL t, x, y, a, b; int main() { cin >> t; while(t--) { cin >> x >> y >> a >> b; LL minn = min(x, y), maxn = max(x, y); LL sum = x + y; LL ans = sum * a <= (minn * b + (maxn - minn) * a) ? sum * a :(minn * b + (maxn - minn) * a); cout << ans << endl; } }
D.Binary Period
题意:给出01组成的字符串,进行寻找新的数组,并且已知数组可以通过对新数组的某个位置的数进行删除得到,并且使其是循环数组,循环的部分长度最短,总长度不超过2n
只有一个数时,周期为1,有两种数时由于 max_lenth <= 2n 循环输出01即可,子序列一定有原字符串
/*00 0101 110 1010 11110 10101010 00001 01010101 */ #include <iostream> #include <cstdio> #include <cstring> using namespace std; char s[666]; int t; int main() { cin >> t; while(t--) { int num0 = 0, num1 = 0; memset(s, 0, sizeof(s)); cin >> s; for(int i = 0;i < strlen(s); ++ i) if(s[i] == '0') num0 ++; else num1++; if(num0 == 0 || num1 == 0){ cout << s << endl; continue; } for(int i = 1;i <= strlen(s); ++ i) { cout << "0" << "1"; } cout << endl; }
E.Nastay and Rice
题目:一共五个数n,a,b,c,d,计算(a-b)~(a+b),是否可以通过乘以n和(c-d)~(c+d)有交集
分情况讨论就可
#include <iostream> #include <cmath> using namespace std; int t, n, a, b, c, d; int main() { cin >> t; while(t--) { cin >> n; cin >> a >> b >> c >> d; int s = abs(a-b), e = a + b; if(s * n > c + d || e * n < abs(c-d)) cout << "NO" << endl; else cout << "YES" << endl; } }
F.Nastay and Door
题意:给你n,k,n个山峰值,山峰巅峰值就是这座山峰值比其他的都高,问在k个相连续的山峰中,山峰巅峰值个数是多少,并且这k个连续山峰中最左边的山峰坐标是多少
a[n] = 1, 2, 3 , 2, 4, 3
b[n] = 0, 0, 1, 1, 2, 2;
b[i-1] - b[i-k+1] 表示从i-k+1 到 i 中峰的个数
b[n] = 0, 0, 1, 1, 2, 2;
b[i-1] - b[i-k+1] 表示从i-k+1 到 i 中峰的个数
if(res < b[i-1] - b[i-k+1]) 就更新 res 和“答案”下标
#include <iostream> using namespace std; const int N = 2e5 + 10; int t, n, k, a[N], b[N]; int main() { cin >> t; while(t--) { cin >> n >> k; for(int i = 1;i <= n; ++ i) cin >> a[i]; int res = 0, flag = 1; for(int i = 2;i <= n; ++ i) { if(i != n && a[i] > a[i+1] && a[i] > a[i-1]) b[i] = b[i-1] + 1; else b[i] = b[i-1]; if(i >= k && b[i-1] - b[i-k+1] > res) res = b[i-1] - b[i-k+1], flag = i-k+1; } cout << res + 1 << " " << flag << endl; } }