Educational Codeforces Round 176 (Rated for Div. 2) (A~D)
前言
D题场上爆写十二发,刚结束就找到问题一发通过...
A. To Zero (签到)
判断一下奇偶,向上取整。
void solve(){
cin >> n >> k;
int res = 0;
if(n % 2 == 1 && k % 2 == 1) {
n -= k;
res++;
}
else if(n % 2 == 1 && k % 2 == 0) {
n -= (k - 1);
res++;
}
if(n <= 0) {
cout << 1 << endl;;
return ;
}
if(k % 2 == 1) k--;
cout << res + (n + k - 1) / k << endl;;
}
B. Array Recoloring (贪心)
题意粘大锅,场上又是看公共,又是看榜,吓得没敢写先去写C了。
题意是先将任意k个元素标记,然后每次可以将一个标记向相邻元素延伸,问最后一个被标记的元素和一开始被标记的元素的和最大值。
如果k==1,那么只能选择数组中一个元素,再在数组两侧选其一。
否则,一定可以以一种方式取出前k+1个大的元素。
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
if(k > 1) {
sort(a + 1, a + n + 1, greater<int>());
int res = 0;
for(int i = 1; i <= k + 1; i++) {
res += a[i];
}
cout << res << endl;
}
else {
int res = 0;
for(int i = 2; i <= n; i++) {
res = max(res, a[1] + a[i]);
}
for(int i = 1; i < n; i++) {
res = max(res, a[n] + a[i]);
}
cout << res << endl;
}
C. Two Colors (贪心)
在m个颜色中选两个涂满栅栏,要求相同颜色连续,且颜色数量有限制。问方案数。
如果确定一种颜色以及要涂多少格,那么另外一种颜色只要满足数量大于等于剩下格子,就可以成功涂满。
因此可以枚举左侧的颜色涂i格,查找有多少个颜色大于等于i,再查找多少个颜色大于等于n-i,然后相乘。
注意一下去重即可。
cin >> n >> m;
vector<int> v;
for(int i = 1; i <= m; i++) {
cin >> a[i];
v.push_back(a[i]);
}
sort(v.begin(), v.end());
int ans = 0;
if(n % 2 == 1) {
for(int i = 1; i <= n / 2; i++) {
int x = lower_bound(v.begin(), v.end(), i) - v.begin();
int y = lower_bound(v.begin(), v.end(), n - i) - v.begin();
x = m - x;
y = m - y;
//cerr << x << " " << y << endl;
ans += (x - 1) * y;
}
ans *= 2;
}else {
for(int i = 1; i < n / 2; i++) {
int x = lower_bound(v.begin(), v.end(), i) - v.begin();
int y = lower_bound(v.begin(), v.end(), n - i) - v.begin();
x = m - x;
y = m - y;
ans += (x - 1) * y;
}
ans *= 2;
int x = lower_bound(v.begin(), v.end(), n / 2) - v.begin();
int y = lower_bound(v.begin(), v.end(), n / 2) - v.begin();
x = m - x;
y = m - y;
ans += (x - 1) * y;
}
cout << ans << endl;
}
D. Palindrome Shuffle (深搜)
保证二进制下两个数分别右移 \(l\),\(r\),使得结果相等。
实际上就是如何用 \(1\)~\(62\) 之间的数填满 \(l\) 和 \(r\) 最优。每个数只能用一次。
写了一个莫名其妙的贪心果不其然挂了。然后想到整数拆分,一个数只能用一次可以保证复杂度。
定义 \(f[i][j][p]\) 表示 \(l\) 还差 \(i\) 位没填,\(r\) 还差 \(j\) 位,目前最大可以使用 \(p\) 。
注意\(vis\)记忆化
注意有特判 \(2,3\), \((2,2)\)是无法拆分的
可能还有其他特判,我这里采取直接先算出ans的最大值。
#include<bits/stdc++.h>
using namespace std;
#define SHOJIG ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n'
#define x1 xxxx
#define y1 yyyy
#define int long long
#define lowbit(x) (x & (-x))
typedef long long ll;
const int N = 1e3 + 9, inf = (1ll << 60);
int n, m, k;
int a[N];
int b[N];
int vis[100][100][100];
int f[100][100][100];
int c[100][100];
int p1, p2;
int same(int i, int j) { //判断分别右移i,j之后是否相等
if(p1 - i != p2 - j) return 0;
for(int x = 0; x + i <= p1; x++) {
if(a[x + i] != b[x + j]) return 0;
}
return 1;
}
void dfs(int l, int r, int p) {
if(l == 0 && r == 0) { // 初始化写搜索里面了
f[l][r][p] = 0;
return;
}
if(vis[l][r][p] == 1) return;
for(int i = 1; i <= p; i++) {
if(l >= i) {
dfs(l - i, r, i - 1);
if(f[l - i][r][i - 1] != -1) {
if(f[l][r][p] == -1) f[l][r][p] = f[l - i][r][i - 1] + (1ll << i);
else f[l][r][p] = min(f[l][r][p], f[l - i][r][i - 1] + (1ll << i));
}
}
if(r >= i) {
dfs(l, r - i, i - 1);
if(f[l][r - i][i - 1] != -1) {
if(f[l][r][p] == -1) f[l][r][p] = f[l][r - i][i - 1] + (1ll << i);
else f[l][r][p] = min(f[l][r][p], f[l][r - i][i - 1] + (1ll << i));
}
}
}
vis[l][r][p] = 1;
}
void solve(){
for(int i = 0; i <= 80; i++) {
a[i] = b[i] = 0;
}
cin >> n >> m;
if(n == m) {
cout << 0 << endl;
return ;
}
p1 = 0; // 二进制化,保留了最高位的0,方便比较使用
while(n) {
a[p1++] = n % 2;
n /= 2;
}
p2 = 0;
while(m) {
b[p2++] = m % 2;
m /= 2;
}
int ans = inf;
ans = (1ll << p1 ) + (1ll << p2 + 1); // 处理特判
for(int i = 0; i <= p1; i++) {
for(int j = 0; j <= p2; j++) {
if(same(i, j)) {
if(c[i][j] != inf)
ans = min(ans, c[i][j]);
}
}
}
cout << ans << endl;
}
signed main(void){
SHOJIG
int _ = 1;
cin >> _;
for(int i = 0; i < 63; i++) {
for(int j = 0; j < 63; j++) {
for(int p = 0; p < 63; p++) {
f[i][j][p] = -1;
}
}
}
for(int i = 0; i < 63; i++) {
for(int j = 0; j < 63; j++) {
for(int p = 0; p < 63; p++) {
dfs(i, j, p);
}
}
}
for(int i = 0; i < 63; i++) { // 计算最后 i,j 的答案
for(int j = 0; j < 63; j++) {
c[i][j] = inf;
for(int p = 0; p < 63; p++) {
if(f[i][j][p] != -1)
c[i][j] = min(c[i][j], f[i][j][p]);
}
}
}
for(int i = 1;i <= _; i++) solve();
}

浙公网安备 33010602011771号