A. Rudolf and the Ticket
思路:按照题意写两重循环模拟即可
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;
int n, m, k;
int a[N], b[N];
void solve()
{
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = 1; i <= m; i++)
{
cin >> b[i];
}
int cnt = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (a[i] + b[j] <= k)
{
cnt++;
}
}
}
cout << cnt << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
B. Rudolf and 121
思路:循环遍历2~n-1,判断是否可以通过操作使得全部数为0,当a[i-1]>a[i]*2时,说明a[i-1]一定不能变成0,否则的话将a[i-1]=0,这样做的代价是a[i]-=2*a[i-1],a[i+1]-=a[i-1],最后判断整个数组是不是为都是0。
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;
int n;
int a[N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
bool ok = true;
for (int i = 2; i <= n - 1; i++)
{
if (a[i - 1] * 2 > a[i]) // 判断是否可以通过操作使得a[i-1]==0
{
ok = false;
break;
}
else // 进行操作后的状态
{
a[i] -= 2 * a[i - 1];
a[i + 1] -= a[i - 1];
a[i - 1] = 0;
}
}
if (a[n - 1] != 0 || a[n] != 0) // 在上面的循环中已经判断了(1~n-2)中的数是否为0
{
ok = false;
}
cout << (ok == true ? "YES" : "No") << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
C. Rudolf and the Ugly String
思路:当在串s中发现“map”或“pie”时,跳过即可,此时cnt+=1
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;
string s;
int n;
void solve()
{
cin >> n >> s;
string t1 = "map", t2 = "pie";
int cnt = 0;
for (int i = 0; i < n; i++)
{
if (s.substr(i, 3) == t1 || s.substr(i, 3) == t2)
{
i += 2;
cnt++;
}
}
cout << cnt << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
D. Rudolf and the Ball Game
比赛时一开始就想到了这个思路,但由于细节有点多,debug了一个小时多。
思路:首先我们用book[]数组表示当book[i]==true时,表示球可能在i位置,我们用t[]数组表示当进行一次操作后从book[]数组中有球的位置转移到操作后有球的位置,最后判断m个操作后book[]中哪个位置有球即可。这么说可能不太清晰,具体还是看代码注释吧。
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;
int n, m, x;
bool book[N], t[N];
void solve()
{
cin >> n >> m >> x;
for (int i = 1; i <= n; i++)
{
book[i] = t[i] = false; // 初始化
}
book[x] = true; // 一开始球在x位置
while (m--)
{
char ch;
int d;
cin >> d >> ch;
if (ch == '?')
{ // 可能顺可能逆
for (int i = 1; i <= n; i++)
{
if (book[i])
{
// 顺时针经过操作后可能有球的位置
if (i + d <= n)
{
t[i + d] = true;
}
else
{
t[i + d - n] = true;
}
// 逆时针经过操作后可能有球的位置
if (i - d > 0)
{
t[i - d] = true;
}
else
{
t[n - (d - i)] = true;
}
}
}
}
else if (ch == '0')
{ // 顺时针
for (int i = 1; i <= n; i++)
{
if (book[i])
{
if (i + d <= n)
{
t[i + d] = true;
}
else
{
t[i + d - n] = true;
}
}
}
}
else if (ch == '1')
{ // 逆时针
for (int i = 1; i <= n; i++)
{
if (book[i])
{
if (i - d > 0)
{
t[i - d] = true;
}
else
{
t[n - (d - i)] = true;
}
}
}
}
for (int i = 1; i <= n; i++)
{
book[i] = t[i]; // 先将t[i]中的状态转移到book[i]中
t[i] = false; // 然后将t[i]设置为false,以便下一次操作进行转移
}
}
int cnt = 0; // 统计答案
for (int i = 1; i <= n; i++)
{
if (book[i])
{
cnt++;
}
}
cout << cnt << '\n';
for (int i = 1; i <= n; i++)
{
if (book[i])
{
cout << i << " ";
}
}
cout << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
E. Rudolf and k Bridges
比赛时没做出来,卡在怎么O(n)的在一行建桥后得到所花费的最小代价,想到用DP,但不会单调队列优化。有了这个之后就简单了,我们只需要有前缀和处理一下,然后从前向后遍历去最小即可。
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ff() flush(stdout)
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int P = 131;
int n, m, k, d;
int sum[N], cost[N], dp[N];
void solve()
{
cin >> n >> m >> k >> d;
for (int i = 1; i <= n; i++)
{
sum[i] = cost[i] = 0;
}
int a[n + 1][m + 1];
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
dp[j] = 0;
}
deque<int> q;
q.clear();
dp[1] = a[i][1] + 1;
q.push_back(1);
for (int j = 2; j <= m; j++)
{
while (!q.empty() && j - q.front() > d + 1)
{
q.pop_front();
}
dp[j] = dp[q.front()] + a[i][j] + 1;
while (!q.empty() && dp[q.back()] > dp[j])
{
q.pop_back();
}
q.push_back(j);
}
cost[i] = dp[m];
}
for (int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + cost[i];
}
int res = 1e18;
for (int i = k; i <= n; i++)
{
res = min(res, sum[i] - sum[i - k]);
}
cout << res << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}