Codeforces Round 1059 (Div. 3)
A. Beautiful Average
题目中n的范围很小,尝试暴力枚举,根据题目中给的公式,计算数组的前缀和,提高运行效率
查看代码void solve(){ int n; cin >> n; vector<int> a(n + 1, 0); for(int i = 1; i <= n; ++i) cin >> a[i]; vector<int> res(n + 1,0); for(int i = 1; i <= n; ++i){ res[i] = res[i - 1] + a[i]; } int maxx = 0; for(int l = 0; l <= n; ++l){ for(int r = l + 1; r <= n; ++r){ if((res[r] - res[l]) / (r - l) > maxx){ maxx = (res[r] - res[l]) / (r - l); } } } cout << maxx << endl; return ; }
B. Beautiful String
查看代码void solve(){ int n; string s; cin >> n >> s; string p = s; reverse(p.begin(), p.end()); if(p == s){ cout << 0 << endl; cout << endl; return ; } vector<vector<int>> G(2); s = ' ' + s; for(int i = 1; i <= n; ++i){ if(s[i] == '0') G[0].emplace_back(i); else G[1].emplace_back(i); } if(!G[0].empty()){ cout << G[0].size() << endl; for(auto x : G[0]){ cout << x << " "; } cout << endl; return ; }else{ cout << G[1].size() << endl; for(auto x : G[1]){ cout << x << " "; } cout << endl; return ; } cout << -1 << endl; return ; }
C. Beautiful XOR
位运算,就是比较二进制位,先判断a和b的二进制位长度,如果b比a长,那么无论怎样变化a都不能变成b。观察a与b的每位二进制位,只有两位互不相等时,加入1ll << i ,才能使a的那位二进制变成b的那位二进制
查看代码void solve(){ int a, b; cin >> a >> b; int idex= 0; while((1ll << idex) <= a) idex++; if(b >= (1ll<< idex)){ cout << -1 << endl; return ; } vector<int> arr; for(int i = 0; i < 32; ++i){ int bita = (a >> i) & 1ll; int bitb = (b >> i) & 1ll; if((bita ^ bitb) == 1){ arr.emplace_back(1ll << i); } } if(arr.empty()){ cout << 0 << endl; return ; }else{ cout << arr.size() << endl; for(auto x : arr){ cout << x << " "; } cout << endl; } return ; }
D. Beautiful Permutation
二分法,第一次通过“1 1 n”得到原始数组的和pre,在通过“2 1 n”得到修改后的数组和sum,则被修改的区间长度就是len = sum - len,通过二分法,每次获取1到mid区间原始数组和修改后数组的和ppre和ssum,如果ppre == ssum 说明修改的区间在mid的右边,让left = mid + 1,如果不相等,则说明部分修改的区间是在1到mid之间的,则让ans = r; r = mid - 1.二分终止后得到的ans就是修改区间的左边,我们一致修改的区间长度为len,则修改区间的右边就为ans + len - 1.
查看代码void solve(){ int n; cin >> n; int pre = (1 + n) * n / 2; cout << "2 1 " << n << endl; int sum; cin >> sum; int len = sum - pre; int l = 1, r = n; int ans = n; while(l <= r){ int mid = (l + r) >> 1; cout << "1 1 " << mid << endl; int ppre; cin >> ppre; cout << "2 1 " << mid << endl; int ssum; cin >> ssum; if(ppre == ssum){ l = mid + 1; }else{ ans = mid; r = mid - 1; } } cout << "! " << ans << " " << ans + len - 1 << endl; return ; }
E. Beautiful Palindromes
这是一道结论题,如果想让加入k个数构成的新数组产生的子回文数最少,那么应该尽可能得让加入的k个数不会与原来的数组产生回文数,也不能让加入的k个数内部产生回文数。因此,我们可以选择3个不同的数“xyz”构成循环,“xyzxyzxyz...”这样排列能确保加入的数内部不会产生回文数,那么,应该如何选取这三个数呢?
根据题目我们能知道,数组元素的取值是在1到n之间的,如果加入一个1到n的数在原数组从来没有出现的数,那么加入的这个数就不会与原数组任何一个数产生回文。如果未出现的数不满足三个,剩下的数应从原数组从后往前记录不同的数直到补全,并且按照顺序排列,比如,对于一个n = 6 的,原数组是【1,2,3,4,4,5】,从未出现的数是6,那么我要补全2个数,从后往前取应该是5与4,如果不想产生回文,我的“xyz”排列应该是645,如果y与z调换,那么这个排列就会与原数组最后两位产生回文。
最后,遍历k次,每遍历3次从来再来,构成循环。
查看代码void solve(){ int n, k; cin >> n >> k; vector<int> a(n + 1, 0); set<int> st; for(int i = 1; i <= n; ++i) { cin >> a[i]; st.insert(a[i]); } vector<int> v; for(int i = 1; i <= n; ++i) if(st.count(i) == 0) v.emplace_back(i); if(st.size() == n){ v = {a[n - 2], a[n - 1], a[n]}; }else if(st.size() == n - 1){ if(a[n] == a[n - 1]) { v.emplace_back(a[n - 2]); v.emplace_back(a[n]); }else{ v.emplace_back(a[n - 1]); v.emplace_back(a[n]); } }else if(st.size() == n - 2){ v.emplace_back(a[n]); } int cnt = 0; for(int i = 0; i < k; ++i){ if(cnt == 3) cnt = 0; cout << v[cnt] << " "; cnt++; } cout << endl; return ; }

浙公网安备 33010602011771号