Codeforces Round #780 (Div. 3)
文章目录
A Vasya and Coins
题意:a个1元,b个2元。问最小不能构成的金额数
答案:a * 1 + b * 2 + 1 (特判0)
void solve() {
int a, b;
cin >> a >> b;
int res = 0;
if(a == 0) res = 1;
else if(b == 0) res = a + 1;
else res = a + b * 2 + 1;
cout << res << endl;
}
B Vlad and Candies
题意:n种糖,每种ai个,每次选择剩余最多的吃(相同则任选)。
并且不能连续吃两个相同的糖,问能否实现,YES or NO
思路:最大和次大差2以上,则按“吃法”会连吃两个最大的。
此题区别于:
《算法竞赛》p166,组合数学的鸽巢原理。
题意:无“吃法”,只要满足不连吃两个相同的糖就行
思路:”隔板法“,最多的糖看成n个隔板,其它糖插入,满足S>=n-1就行,YES
(S:除去最多糖的其余糖数)
(n:最多糖数)
int a[N];
void solve() {
int n; cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
if(n == 1 && a[0] >= 2) {
puts("NO");
return ;
}
sort(a, a + n);
if(a[n - 1] - a[n - 2] >= 2) puts("NO");
else puts("YES");
}
C Get an Even String
题意:删除任意位置字符,使得最后字符“成偶”,问最少步数。
思路:最优转化:最近(最内部)的偶数个会保留不删。(自己的理解hh)
例如:dacaddbb
答案:会选则删d,c,留aaddbb,最有转化即内部aa保留,优于删aa两侧的dd
==详见代码==
样例:
6
aabbdabdccc
zyx
aaababbb
aabbcc
oaoaaaoo
bmefbmuyw
输出:
3
3
2
0
2
7
void solve() {
int cnt[26] = {0};
string s; cin >> s;
int n = s.sz, ans = 0;
for (int i = 0; i < n; i++) {
++cnt[s[i] - 'a'];
if(cnt[s[i] - 'a'] == 2) {
ans += 2;
memset(cnt, 0, sizeof cnt);
}
}
cout << n - ans << endl;
}
D Maximum Product Strikes Back
题意:n个数ai,(-2<=ai<=2),问删前后缀,使得最后剩余数的连积最大。
思路:按0分块隔开,每块考虑偶数or奇数个负数的情况。
对于偶数,当然全留!(统计|2|的个数)
对于奇数,只需看第一个负,倒一个负左右的情况
int n, ans, x, y;
int a[N];
// 处理偶数个负数的情况,直接就是统计2的个数
void update(int l, int r) {
if(l > r) return ;
int res = 0;
for (int i = l; i <= r; i++) if(abs(a[i]) == 2) res++;
if(res >= ans) x = l - 1, y = n - r, ans = res;
}
void work(int l, int r) {
int cnt = 0;
for (int i = l; i <= r; i++) if(a[i] < 0) cnt++;
if(cnt % 2 == 0) update(l, r);
else {
// 分别对前后最大的偶数个负数情况讨论
int now = l;
while(a[now] > 0 && now < r) now++;
update(l, now - 1);
update(now + 1, r);
now = r;
while(a[now] > 0 && now > l) now--;
update(l, now - 1);
update(now + 1, r);
}
}
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
a[n + 1] = 0; // 1 1 1 保证能把这块丢进work,最后置0
x = n, y = ans = 0;
for (int i = 1, j = 1; i <= n + 1; i++) {
if(a[i] == 0) {
if(i - j > 0) work(j, i - 1);
j = i + 1;
}
}
cout << x << ' ' << y << endl;
}
E Matrix and Shifts
题意:给定01矩阵,能上下左右的一行(列)循环换位,不造成代价。
也可以对任意位进行xor,为最后主对角线全1的最小代价。
思路:循环换位,等价于,拼接矩阵,[] == [][][][] ,n*n 变 2n*2n
答案:矩阵中1的个数 - 对角线上1的个数 +(0的xor次数)(n - 对角线上1的个数)
#include <iostream>
#include <cstring>
using namespace std;
const int N = 4010;
char g[N][N];
int a[N][N];
int s[N][N], p[N][N]; // s是矩阵中1的个数的前缀和,p是对角线上1的个数的前缀和
// 答案是矩阵中1的个数-对角线上1的个数 + (n - 对角线上1的个数)
// 那些操作可以转换成复制三遍这个矩阵,组成一个2n*2n的矩阵,枚举每个n*n的矩阵
void solve()
{
int n, m;
scanf("%d", &n);
m = n * 2;
for(int i = 1; i <= n; i ++ ) scanf("%s", g[i] + 1);
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ )
a[i][j] = a[i][j + n] = a[i + n][j] = a[i + n][j + n] = g[i][j] - '0';
// 二维前缀和记录矩阵中1的个数
for(int i = 1; i <= m; i ++ )
for(int j = 1; j <= m; j ++ )
{
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
p[i][j] = p[i - 1][j - 1] + a[i][j];
}
int ans = n * n;
for(int i = n; i <= m; i ++ )
for(int j = n; j <= m; j ++ )
{
int sum = s[i][j] - s[i][j - n] - s[i - n][j] + s[i - n][j - n];
int psum = p[i][j] - p[i - n][j - n];
ans = min(ans, sum + n - 2 * psum);
}
printf("%d\n", ans);
return;
}
int main()
{
int t; scanf("%d", &t);
while(t --)
{
solve();
}
return 0;
}
F1 Promising String (easy version)
题意:给定字符串s,(s只含“+”,“-”),等价规则:“--”能和“+”等价。
问s的所有非空子串有多少个平衡串。(平衡串:“+”=1,“-”=-1,之和为0的串为平衡串)
思路:发现平衡串就是,k * 0 or k * -3 ,和值为这两种就一定是平衡的。
void solve() {
int n; cin >> n;
string s; cin >> s;
int cnt = 0;
for (int i = 0; i < n; i++) {
int res = 0;
for (int j = i; j < n; j++) {
res += s[j] == '+' ? 1 : -1;
if(res == 0) cnt++;
if(res < 0) {
int x = res * -1;
if(x / 3 * 3 == x) cnt++;
}
}
}
cout << cnt << endl;
}
不配了