2025“钉耙编程”中国大学生算法设计春季联赛 - 热身赛

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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值