Codeforces Round 642 (Div3)
K-periodic Garland
给定一个长度位
的 串,每次操作可以将 变为 或者将 变为 ,现在你需要通过操作使得所有 之间的距离为 ,求最少的操作次数,注意全为 也算
题解: / 贪心 : 最大子段和思想
方法一:
状态表示:
:代表将区间 变为合法串的最小操作次数,且第 位为 状态转移:
- 贪心考虑只有两种情况的时候我们可以将第
位变成 :
- 若第
位也是 ,我们可以考虑将第 位变为 ,那么我们需要将 中的所有1变为0 - 我们同样可以考虑使第
位前面所有的1变为0,从第 位的 重新当作起始位置,那么我们需要将前面所有的1变为0 - 同时如果该位本身不是
,我们需要将其变为
- 同样只有两种情况我们可以将第
位变为 :
- 第
位是1的情况 - 第
位是0的情况 - 如果第
位不是0,我们需要将其变为0
状态初始:
方法二:贪心 + 枚举对
余数 由题意可知这些
一定是连续的且距离间隔 ,这说明1所处的位置对 取模的模数是相同的,且这些1连续,所以我们可以考虑根据对 的余数来枚举 的起始位置,所以我们不妨先将所有的1变为0 我们设
:可以减免的答案贡献,或者说从起始位置到现在1的前缀和数量与0的前缀和数量之差;
- 对于某一位来说,我们需要其为1,并且其本身已经为1,说明我们原本不用将其变为0,所以这部分答案可以减免,
++, - 对于某一位来说,我们需要其为1,但是其本身为0,说明我们这部分答案不能减免,
--, - 如果
,说明从起始位置开始0的数量已经比1的数量多了,也就是说我们将这些前面位置都变成1就比全部变为0吃亏,倒不如全部变为0,借用最大子段和的思想我们直接舍弃前面的部分,将该位置重新当成起始位置, - 我们在枚举过程中始终维护
的最大值即可 时间复杂度为调和级数:
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10;
int n, k;
int f[N][2];
int pre[N];
void solve()
{
cin >> n >> k;
string s;
cin >> s;
s = " " + s;
for (int i = 1; i <= n; ++i)
pre[i] = pre[i - 1] + (s[i] == '1');
for (int i = 1; i <= n; ++i)
{
f[i][1] = min(f[max(0ll, i - k)][1] + pre[i - 1] - pre[max(0ll, i - k)], pre[i - 1]) + (s[i] == '0');
f[i][0] = min(f[i - 1][1], f[i - 1][0]) + (s[i] == '1');
}
cout << min(f[n][0], f[n][1]) << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10;
int n, k;
void solve()
{
cin >> n >> k;
string s;
cin >> s;
s = " " + s;
int ans = 0;
for (int i = 1; i <= n; ++i)
if (s[i] == '1')
ans++;
int maxx = -INF;
for (int i = 1; i <= k; ++i)
{
int cnt = 0;
for (int j = i; j <= n; j += k)
{
if (s[j] == '1')
cnt++;
else
cnt--;
if (cnt < 0)
cnt = 0;
maxx = max(cnt, maxx);
}
}
cout << ans - maxx << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
Decreasing Heights
给出一个
的矩阵,每个矩阵的权值代表该点的初始高度。 现在需要从点
走到点 ,每一步需要满足以下条件:
- 只能向右或向下
- 设当前格子的高度为
,只能移动到高度为 的格子上去 初始时可以进行操作,使得某个格子的高度减少一个单位。
问最少需要进行多少次操作,可以存在至少一条从点
到点 的路线
题解: + 枚举
我们发现只要确定起点
的高度,那么对于任意位置 的高度我们都是确定的: ,所以我们只需要枚举起点的高度即可,但是我们怎么枚举? 我们贪心的进行枚举,每次枚举的起点高度能够保证使得位置
上的高度不需要降低,即起码保证有一个位置我们不需要改变其高度,如果这个位置原有的高度 ,且 ,说明我们不能通过降低起点的高度使得到达 时不需要降低 的高度,否则我们可以利用 求出从起点到终点的最小操作次数 设起点高度为
状态表示:
:从起点 到达 所需的最小操作次数 状态转移:
- 该位置是从上面过来的,即
- 该位置是从右边过来的,即
- 如果$ a[i][j]<h+i+j-2
(i,j)$无法到达,我们直接跳过即可
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e2 + 10, M = 4e5 + 10;
int n, m;
int a[N][N];
int calc(int x, int y)
{
vector<vector<int>> f(n + 10, vector<int>(m + 10, INF));
int h = a[x][y] - x - y + 2;
f[1][1] = a[1][1] + x + y - 2 - a[x][y];
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
int cur = h + i + j - 2;
if (cur > a[i][j])
continue;
f[i][j] = min(f[i][j], f[i - 1][j] + a[i][j] - cur);
f[i][j] = min(f[i][j], f[i][j - 1] + a[i][j] - cur);
}
}
return f[n][m];
}
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> a[i][j];
int ans = INF;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
if (a[1][1] + i + j - 2 < a[i][j])
continue;
ans = min(ans, calc(i, j));
}
}
cout << ans << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话