前言:不要忘记特判1。。。
值钱的项链
一个环,环上每个点有两种选择,蓝色或红色,都有不同的价值,要求不能两个连着的红色。
很容易想到:
f[i][0] = max(f[i - 1][0], f[i - 1][1]) + v[i][0].val;
f[i][1] = f[i - 1][0] + v[i][1].val;
然后第一个点设置红色和蓝色,跑两次dp就出答案了。
坑点:
蓝(无) 蓝(有) 蓝(有)
红(有) 红(有,很大)
这样第三个蓝如果继承了第二个红,那就出问题了。
有两种方法,一种是dp数组初始化-1e18,另一种是如果要继承的那个值不是-1,那就继承,不然就不继承。
第二种好像会好些,毕竟-1e18容易在某些不为人知的地方溢出(
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5, mod = 1e9 + 7;
struct node{
int val, co;
};
vector<node> v[N];
int f[N][2], g[N][2];
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 0; i <= n; i++) {
g[i][0] = g[i][1] = -1e18;
f[i][0] = f[i][1] = -1e18;
v[i].clear();
}
if (m == 0 || n == 0) {
printf("-1\n");
return;
}
for (int i = 1; i <= n; i++) v[i].resize(m + 1);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> v[i][j].val;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> v[i][j].co;
}
}
// for (int i = 1; i <= n; i++) {
// for (auto j : v[i]) {
// cout << j.co << " " << j.val << " ";
// }
// puts("");
// }
for (int i = 1; i <= n; i++) {
node red, blue;
red.val = -1, blue.val = -1;
red.co = 1, blue.co = 0;
for (int j = 1; j <= m; j++)
{
if (v[i][j].co) {
if (v[i][j].val > red.val) red = v[i][j];
}
else {
if (v[i][j].val > blue.val) blue = v[i][j];
}
}
v[i].clear();
if (blue.val != -1) v[i].push_back(blue);
if (red.val != -1) v[i].push_back(red);
}
if (n == 1) {
if (v[1].size() > 1)
printf("%lld\n", max(v[1][0].val, v[1][1].val));
else
printf("%lld\n", v[1][0].val);
return;
}
bool ok = 1;
for (int i = 1; i < n; i++) {
if (v[i].size() == 1 && v[i + 1].size() == 1 && v[i][0].co && v[i + 1][0].co)
ok = 0;
}
if (v[1].size() == 1 && v[n].size() == 1 && v[1][0].co && v[n][0].co)
ok = 0;
if (v[1].size() && v[1][0].co == 0) {
f[1][0] = v[1][0].val;
for (int i = 2; i <= n; i++) {
if (v[i].size() > 1) {
f[i][0] = max(f[i - 1][0], f[i - 1][1]) + v[i][0].val;
f[i][1] = f[i - 1][0] + v[i][1].val;
}
else if (v[i][0].co) f[i][1] = f[i - 1][0] + v[i][0].val;
else f[i][0] = max(f[i - 1][0], f[i - 1][1]) + v[i][0].val;
}
}
if ((v[1].size() && v[1][0].co == 1) || (v[1].size() > 1 && v[1][1].co == 1)){
if(v[1].size() && v[1][0].co == 1)
g[1][1] = v[1][0].val;
if(v[1].size() > 1 && v[1][1].co == 1)
g[1][1] = v[1][1].val;
for (int i = 2; i <= n; i++) {
if (v[i].size() > 1) {
g[i][0] = max(g[i - 1][0], g[i - 1][1]) + v[i][0].val;
g[i][1] = g[i - 1][0] + v[i][1].val;
}
else if (v[i][0].co) g[i][1] = g[i - 1][0] + v[i][0].val;
else g[i][0] = max(g[i - 1][0], g[i - 1][1]) + v[i][0].val;
}
}
int ans = max({g[n][0], f[n][0], f[n][1]});
if (ok)
printf("%lld\n", ans);
else
printf("-1\n");
for (int i = 1; i <= n; i++) {
g[i][0] = g[i][1] = -1e18;
f[i][0] = f[i][1] = -1e18;
v[i].clear();
}
}
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
int tt;
cin >> tt;
while(tt--) solve();
return 0;
}
平衡的字符串
画了画发现,如果不考虑问号,只包含0和1,那一个串重复很多次的结果,每个长度为k的子串才会0 1都相等。
所以直接判开头长为k的串是否在接下来的时候都出现就好了。
坑点:如果这个长为k的串不够合法,那也是-1,判定他不合法的时候,会有一些问号在后续的遍历中是已经确定的值,不能统计为问号了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5, mod = 1e9 + 7;
char s[N];
signed main()
{
int n, k;
cin >> n >> k;
scanf("%s", s + 1);
bool ok = 1;
int cnt0 = 0, cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= k; i++) {
int f1 = 0, f2 = 0;
for (int j = 0; j * k + i <= n; j++) {
if (s[j * k + i] == '1') f1 = 1;
else if (s[j * k + i] == '0') f2 = 1;
}
if (f1 && f2) ok = 0;
if (f1) cnt0++;
else if (f2) cnt1++;
else cnt2++;
}
if (abs(cnt0 - cnt1) > cnt2 || (cnt2 & 1)) ok = 0;
if (ok) puts("Yes");
else puts("No");
return 0;
}