1003 找回x
这个题目我们可以观察到变量有点多。所以我们可以考虑一下和,或者一些不变的东西。可以求一下他的和。A 的和,B 的和,C 的和求出来之后,可以求出来 x。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 2e5 + 10;
void solve()
{
int n;
cin >> n;
i64 sa = 0, sb = 0, sc = 0;
for (int i = 1; i <= n; i++)
{
i64 x;
cin >> x;
sa += x;
}
vector<i64> b(n + 1);
for (int i = 1; i <= n; i++)
cin >> b[i], sb += b[i];
vector<i64> c(n + 1);
for (int i = 1; i <= n; i++)
cin >> c[i], sc += c[i];
cout << (sc - sb) / sa << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
1006 对吗?对的对的 不对不对
可以算一下前缀各个字符的和,后缀各个字符的和。用 dp 来计算一下 YES 和 NO 的和。
然后依次判断每一位变为 Y E S N O 之后,数量的变化即可。
这种求前缀字符的和和后缀字符的和是非常经典的。
for (int i = 1; i <= len; i++)
{
for (int j = 0; j < 26; j++)
s1[i][j] = s1[i - 1][j];
s1[i][s[i] - 'A']++;
}
求 YES 和 NO 的时候实际上是求前缀的和。
如果出现 E 那么答案就是s1[i-1][‘Y’-‘A’] * s2[i+1][‘S’-‘A’];
这两道 dp 都是非常好的。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 2e5 + 10;
i64 preYE[N], sufES[N];
string s;
int s1[N][26], s2[N][26]; // s1 为前缀字符数量和,s2 为后缀字符数量和
i64 sum1, sum2;
int ck(int wz, char ch)
{
i64 u1 = sum1, u2 = sum2;
// 分别对 wz 是什么字符,先减去,然后根据 ch 是什么再加上。
if (s[wz] == 'Y')
u1 -= sufES[wz + 1];
else if (s[wz] == 'E')
u1 -= (i64)s1[wz - 1]['Y' - 'A'] * s2[wz + 1]['S' - 'A'];
else if (s[wz] == 'S')
u1 -= preYE[wz - 1];
else if (s[wz] == 'N')
u2 -= s2[wz + 1]['O' - 'A'];
else if (s[wz] == 'O')
u2 -= s1[wz - 1]['N' - 'A'];
if (ch == 'Y')
u1 += sufES[wz + 1];
else if (ch == 'E')
u1 += (i64)s1[wz - 1]['Y' - 'A'] * s2[wz + 1]['S' - 'A'];
else if (ch == 'S')
u1 += preYE[wz - 1];
else if (ch == 'N')
u2 += s2[wz + 1]['O' - 'A'];
else if (ch == 'O')
u2 += s1[wz - 1]['N' - 'A'];
if (u1 > u2)
return 1;
else if (u1 < u2)
return 2;
return 0;
}
void solve()
{
sum1 = 0;
sum2 = 0; // sum1 是 yes 的数量,sum2 是 no 的数量
memset(s1, 0, sizeof s1);
memset(s2, 0, sizeof s2);
memset(preYE, 0, sizeof preYE);
memset(sufES, 0, sizeof sufES);
cin >> s;
s = "#" + s;
int len = s.length() - 1;
// for (int i = 1; i <= len; i ++) cout << s[i];
// cout << "\n";
for (int i = 1; i <= len; i++)
{
for (int j = 0; j < 26; j++)
s1[i][j] = s1[i - 1][j];
s1[i][s[i] - 'A']++;
}
for (int i = len; i >= 1; i--)
{
for (int j = 0; j < 26; j++)
s2[i][j] = s2[i + 1][j];
s2[i][s[i] - 'A']++;
}
// cout << 6;
for (int i = 1; i <= len; i++)
{
preYE[i] = preYE[i - 1];
if (s[i] == 'E')
sum1 += (i64)s1[i - 1]['Y' - 'A'] * s2[i + 1]['S' - 'A'], preYE[i] += s1[i - 1]['Y' - 'A'];
else if (s[i] == 'O')
sum2 += s1[i - 1]['N' - 'A'];
}
sufES[len + 1] = 0;
for (int i = len; i >= 1; i--)
{
sufES[i] = sufES[i + 1];
if (s[i] == 'E')
sufES[i] += s2[i + 1]['S' - 'A'];
}
cout << sum1 << " " << sum2 << "\n";
if (sum1 == sum2)
{
cout << "DUI DUI DUIMA" << "\n";
return;
}
if (sum1 < sum2)
{
for (int i = 1; i <= len; i++)
{
if (ck(i, 'Y') == 1 || ck(i, 'E') == 1 || ck(i, 'S') == 1)
{
cout << "O DUI DE" << "\n";
return;
}
}
}
else
{
for (int i = 1; i <= len; i++)
{
if (ck(i, 'N') == 2 || ck(i, 'O') == 2)
{
cout << "O BUDUI BUDUI" << "\n";
return;
}
}
}
if (sum1 < sum2)
{
cout << "BUDUI BUDUI" << "\n";
}
else
cout << "DUI DE" << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
1008 金牌
让金牌的数量加上 min(Ag, Cu) 的数量即可。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 2e5 + 10;
void solve()
{
int n; cin >> n;
string s;
int ans = 0, cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= n; i ++)
{
cin >> s;
if (s == "Au") ans ++;
if (s == "Ag") cnt1 ++;
if (s == "Cu") cnt2 ++;
}
cout << ans + min(cnt1, cnt2) << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while (t --)
{
solve();
}
return 0;
}
1009 A进制
这道题有一个比较重要的点。就是求 A 进制。可以通过求递归来求递归。
就比如这个 ** int pyu(int x) {return pho(x / a) * a;}** 这个东西可以把它转化为 A 进制。
然后就是用 dp 来求和。 dp[i][j] 表示第 i 轮,数字 j 是否出现。最后加上 dp[n][j] == true 就行了。
dp 不要忘记初始化。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 2e5 + 10;
int yu[2005][2005], ho[2005][2005], yh[2005][2005];
bool dp[2005][32768];
int n, a, x;
int pyu(int x, int y)
{
if (x <= 1023 && y <= 1023)
return yu[x][y];
return pyu(x / a, y / a) * a + min(x % a, y % a);
}
int pho(int x, int y)
{
if (x <= 1023 && y <= 1023)
return ho[x][y];
return pho(x / a, y / a) * a + max(x % a, y % a);
}
int pyh(int x, int y)
{
if (x <= 1023 && y <= 1023) return yh[x][y];
return pyh(x / a, y / a) * a + (x + y) % a;
}
void solve()
{
memset(yu, 0, sizeof yu);
memset(ho, 0, sizeof ho);
memset(yh, 0, sizeof yh);
memset(dp, 0, sizeof dp);
cin >> n >> a >> x;
for (int i = 0; i <= 1023; i++)
{
for (int j = 0; j <= 1023; j++)
{
yu[i][j] = yu[i / a][j / a] * a + min(i % a, j % a);
ho[i][j] = ho[i / a][j / a] * a + max(i % a, j % a);
yh[i][j] = yh[i / a][j / a] * a + ((i + j) % a);
}
}
// cout << n << a << x << "\n";
dp[0][x] = 1; // 不要忘记初始化。
for (int i = 1; i <= n; i ++)
{
int u;
cin >> u;
for (int j = 0; j <= 32766; j ++)
{
if (!dp[i - 1][j]) continue;
dp[i][pyu(u, j)] = 1;
dp[i][pho(u, j)] = 1;
dp[i][pyh(u, j)] = 1;
}
}
int ans = 0;
for (int i = 1; i <= 32767; i ++)
if (dp[n][i]) ans += i;
cout << ans << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
1010 绝对值
[l, r] 是 l, r 的区间和的绝对值。
这句话的话其实是把任意长度的序列划分为。若干段。
[xi + 1, xi] 是不包含左边的序列。比如说 (1,2) (3, 5) (6, 9) 这样。 你把这个理解为子序列就可以了。
代码的话就是把所有的前缀和直接取一下绝对值就可以了。 其实还算比较简单。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 2e5 + 10;
void solve()
{
int n; cin >> n;
vector<i64> a(n + 1);
for (int i = 1; i <= n; i ++)
{
cin >> a[i];
a[i] < 0? a[i] = -a[i] : a[i];
}
vector<i64> s(n + 1);
for (int i = 1; i <= n; i++) s[i] = a[i] + s[i - 1];
i64 ans = 0;
for (int i = 1; i <= n; i ++) ans += abs(s[i]);
cout << ans << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while (t --)
{
solve();
}
return 0;
}