散题
2024牛客暑期多校训练营2 H Instructions Substring
时间:2024-07-18
标签:前缀和、map
题意
初始在\((0,0)\)处,给一串操作,给目标位置,要求有多少操作能经过当前位置
也就是说在到达目标位置后的所有操作都算
思路
考虑用map维护前缀和,样例ASAWDD
可以构建:\(((-1,0),1),((-1,-1),2),((-2,-1),3),((-2,0),4),((-1,0),5),((0,0),6)\)
存储当前的位置前缀和和下标
然后开始枚举起点
比如从第二个A开始,当前处于 \((-2,-1)\) ,所以需要到达\((-1,0)\),在map中寻找后找到下标5
那么对答案的贡献就是 \(n-5+1\)
注意需要存储下标来寻找在当前位置往后的可行的点,并且要是最小的可行点才能保证答案最优
所以配合二分(lower_bound)
最后注意对 \((0,0)\) 特判,因为对于初始点,每次都能找到自己,但是自己是不需要\(n-i+1\)
只需要\(n-i\) ,所以也可以选择在 \(if (p != mp[target].end())\) 判定内加一个不等于自身的判定
代码
#include<bits/stdc++.h>
using namespace std;
#define YES "Yes"
#define NO "No"
#define int long long
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define rep(i,j,k) for(i=(j);i<(k);i++)
#define all(x) x.begin(),x.end()
#define vi vector<int>
typedef pair<int, int> pii;
const int N = 2e5 + 10;
int n;
string s;
int sw, ad;
void deal(pii & p,int i) {
if (s[i] == 'W')p.second++;
if (s[i] == 'S')p.second--;
if (s[i] == 'A')p.first--;
if (s[i] == 'D')p.first++;
}
void solve() {
cin >> n >> sw >> ad;
cin >> s;
// 特判
if ( sw==0 && ad==0) {
cout << n * (n + 1) / 2 << endl;
return;
}
map<pii, vi>mp;
pii cur = { 0,0 };
mp[cur].emplace_back(0);
for (int i = 0; i < n; i++) {
deal(cur, i);
mp[cur].emplace_back(i + 1);
}
int ans = 0;
cur = { 0,0 };
for (int i = 0; i < n; i++) {
//cur要到x,y位置
pii target = { cur.first + sw,cur.second + ad };
//先看有没有target
if (mp.count(target)) {
auto p = lower_bound(mp[target].begin(), mp[target].end(), i);
// 再看看这个target是不是在当前的后面,如果在当前的前面,那是无法到达的
// 在当前的前面也就是找不到的情况
//if (*p == i) {
//ans += n - *p;
//}
//else {
ans += n - *p + 1;
//}
}
deal(cur, i);
}
cout << ans;
}
signed main() {
IOS;
solve();
return 0;
}
D - Grid Puzzle
时间:2024-07-20
原题:Codeforces Round 960 (Div. 2)
标签:贪心
题意
有 \(n\times n\) 的矩阵,给出第i行前 \(a_i\) 个是黑色
每次可以选择两种操作,把\(2 \times 2\)的格子涂成白色或者某一行涂成白色
思路
首先对于5以上的,不用说肯定是涂一行,因为五以上要三次,一行只需要2次,这是很直觉性的
现在讨论5以下,对于小于等于2的,进行涂色,同时要处理下一行的格子数
如果大于2,直接答案+1
比如当前是1 3,处理了1后,第二行由于也被涂色,会变成1,也被涂色,所以答案+2
如果当前是3 3,遇到第一行,答案+1,遇到第二行,答案+1,答案不变
实质上这是贪心的做法,不过要发现2的特殊性,然后多尝试
代码
#include <bits/stdc++.h>
using namespace std;
#define YES "Yes"
#define NO "No"
#define int long long
#define ull unsigned long long
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define rep(i, j, k) for (i = (j); i < (k); i++)
#define all(x) x.begin(), x.end()
#define vi vector<int>
typedef pair<int, int> pii;
const int MOD = 1000000007;
const int N = 2e5 + 10;
int ii, jj, kk;
int n;
// 涂色的格子
int arr[N][6];
// 输入的数据
int a[N];
void solve() {
cin >> n;
int temp;
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 5; j++) {
arr[i][j] = 0;
}
}
rep(ii, 0, n) {
cin >> a[ii];
// 只有当一行的格子数小于5时才需要考虑是否用1
if (a[ii] < 5) {
rep(jj, 0, a[ii]) {
arr[ii][jj] = 1;
}
} else {
a[ii] = 0;
ans++;
}
}
for (int i = 0; i < n; i++) {
if (a[i] == 0)
continue;
if (a[i] > 2)
ans++;
else
for (int j = 0; j < 4; j++) {
if (arr[i][j] == 1) {
arr[i][j] = 0;
arr[i][j + 1] = 0;
if (arr[i + 1][j] == 1) {
arr[i + 1][j] = 0;
a[i + 1]--;
}
if (arr[i + 1][j + 1] == 1) {
arr[i + 1][j + 1] = 0;
a[i + 1]--;
}
ans++;
}
}
}
cout << ans << endl;
}
signed main() {
IOS;
int t = 1;
cin >> t;
while (t--) {
// cout << "Case #" << t + 1 << ": ";
solve();
}
return 0;
}
星星
时间:2024-07-19
标签:二维dp
题意
每轮可以选择获得0到5颗星星,但是每轮每个星星的代价不同
要求n轮后正好拥有k颗星星,求最小代价
思路
直接就是一手2维dp,就是初始化怎么搞
代码
#include <bits/stdc++.h>
using namespace std;
#define YES "Yes"
#define NO "No"
#define int long long
#define endl "\n"
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#define rep(i, j, k) for (i = (j); i < (k); i++)
#define all(x) x.begin(), x.end()
#define vi vector<int>
#define pii pair<int, int>
const int MOD = 1000000007;
const int N = 1010;
int ii, jj, kk, n, k;
int a[N], b[N], c[N], d[N];
// 表示当前回合已经获得的糖数
int dp[N][4 * N] = {0};
void solve() {
cin >> n >> k;
rep(ii, 1, n + 1) {
cin >> a[ii] >> b[ii] >> c[ii] >> d[ii];
}
// 考虑到dp[i][j]依赖于上一层的j-4到j,层层依赖,所以初始将第0层修改为max
for (int i = 0; i <= k; i++)
dp[0][i] = 1e18;
// 对于0层的0置0
dp[0][0] = 0;
for (int i = 1; i <= n; i++) {
dp[i][0] = 0;
for (int j = 1; j <= k; j++) {
dp[i][j] = dp[i - 1][j];
if (j > 0)
dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + a[i]);
if (j > 1)
dp[i][j] = min(dp[i][j], dp[i - 1][j - 2] + b[i]);
if (j > 2)
dp[i][j] = min(dp[i][j], dp[i - 1][j - 3] + c[i]);
if (j > 3)
dp[i][j] = min(dp[i][j], dp[i - 1][j - 4] + d[i]);
}
}
cout << dp[n][k] << endl;
}
signed main() {
IOS;
int t = 1;
cin >> t;
while (t--)
solve();
return 0;
}