Educational Codeforces Round 154 (Rated for Div. 2)
C
题意:
一开始有个空数组,以及一串操作s:
s[i] = +:向空数组末尾中加入一个数
s[i] = -:在数组末尾减去一个数
s[i] = 1:当前数组是递增数组
s[i] = 0:当前数组不是递增数组
问s是否是合法的操作
思路:
非法操作说明当前的 0 和 1 冲突了,当前查询和上一次查询冲突了,因为只关心之前的数组状态,所以令b[len]表示数组长度为len时要求的状态,b[len] = 1表示要求数组长度为len时是递增,b[len] = -1表示要求数组长度为len时是不递增的,b[len] = 0 表示没要求
inline void solve()
{
string s; cin >> s;
std::vector<int> b(s.size() + 1);
int len = 0;
bool ans = true;
b[0] = 1, b[1] = 1;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '+')
{
if (b[len] == -1) b[len + 1] = -1;
len++;
}
if (s[i] == '-')
{
if (b[len] == 1 && len >= 2)
{
b[len] = 0;
b[len - 1] = 1;
}
if (b[len] == -1)
{
b[len] = 0;
}
len--;
if (len < 0)
{
ans = false;
break;
}
}
if (s[i] == '1')
{
if (b[len] == -1)
{
ans = false;
break;
}
b[len] = 1;
}
if (s[i] == '0')
{
if (len < 2)
{
ans = false;
break;
}
if (b[len] == 1)
{
ans = false;
break;
}
b[len] = -1;
}
}
if (ans) cout << "YES" << endl;
else cout << "NO" << endl;
}
D
题意:
给定一个数组,每次操作可以选择三个数l, r, x; 让区间[l, r]的数都乘以x,问最少多少次操作可以让数组变成严格单调递增
思路:
因为x可以任意选,所以最终数组中每个数都要么是{负无穷,原数,正无穷}中的一个,定义状态方程为f[i][j]: 让前i个数单调且第i个数的情况为j的最少操作数
f[i][0]: 负无穷, f[i][1]: 原数,f[i][2]: 正无穷
转移方程:先区分a[i]和a[i - 1]的大小,以及当前状态可以由哪些状态转移过来
inline void solve()
{
int n; cin >> n;
std::vector<int> a(n);
memset(f, 0x3f, sizeof(f));
for (int i = 0; i < n; i++)
cin >> a[i];
f[0][0] = 1; f[0][1] = 0; f[0][2] = 1;
for (int i = 1; i < n; i++)
{
if (a[i] >= a[i - 1]) f[i][0] = f[i - 1][0] + 1; // 负数要反过来,因为大数乘上负数就变小了
else f[i][0] = f[i - 1][0];
if (a[i] > a[i - 1])
{
f[i][1] = min(f[i - 1][0], f[i - 1][1]);
f[i][2] = min(min(f[i - 1][0], f[i - 1][1]) + 1, f[i - 1][2]);
}
else
{
f[i][1] = f[i - 1][0];
f[i][2] = min(min(f[i - 1][0], f[i - 1][1]), f[i - 1][2]) + 1;
}
}
int ans = inf;
for (int i = 0; i < 3; i++)
ans = min(ans, f[n - 1][i]);
cout << ans << endl;
}

浙公网安备 33010602011771号