AtCoder Beginner Contest 182 AtCoder Beginner Contest 182

导读:
简单的题目,只说明题意,或者直接说明结论
下面的难题,会做详细的解释和证明
立个flag,在座的大佬们做个见证:一个月刷60场ABC,现在2021/7/7,第二十二天,已打卡十八场。

F - Valid payments

题意:有n中面值的货币a[i],其中满足a[1] = 1, a[i+1]都是a[i]的倍数。
现在有一种价格为x的商品,付款y元,找零y-x元
问满足一下两种条件的方案数为多少
1.付款和找零的货币数量在对应金额下为最少
2.付款时使用的货币面值在找零的时候就不可以在使用。

解决:
首先对于条件1,我们可以得出每个面值的货币最大的使用数量,也就是mx[i] = a[i + 1] / a[i]
证明,假设某种货币i使用次数大于mx[i]的时候,我们可以用a[i + 1]来代替。
其次,每个面值都可以被唯一的表达,上面的论证同样可以证明这里的作用。
那么,我们可以将x+b=y表示为:
b1a1 + b2a2 + … + bnan
+x1a1 + x2a2 + … + xnan
=y1a1 + y2a2 + … + ynan
其中,有条件2可知。如果bi为非0数,那么yi一定为0,如果bi为0,yi可以为0,也可以不为0.要保证bi和yi不同时为非0数。
因为x是唯一确定的,所以,如果b确定了,那么y也一定是确定的,所以,询问有多少中方案数,也就是问可以组成多少个合法的b或者合法的y,
可以用DP解决,dp[i][0/1]表示当前位i是否进位(0表示不进位)的b的方案数
如果当前位没有进位,那么,
1.第i+1位一定可以不进位(如果我让b[i]为0,就不用进位了)
2.若第i+1位想进位,一定要让x为正值,让b[i + 1]值为mx[i]-1就可以了
如果当前位有进位,那么
1.第i+1位一定可以进位,(因为i位有进位,我让b[i + 1]为mx[i]-1就可以了
2.若第i+1为想不进位,一定要让x[i + 1] + 1小于mx[i + 1]。(让b[i+1]等于0就可以了)
下面是代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 55;
ll n, x;
ll a[N];
ll mx[N], xx[N];
ll dp[N][2];
int main()
{
  cin >> n >> x;
  for (int i = 1; i <= n; i ++ ) cin >> a[i];
  for (int i = 1; i < n; i ++ ) mx[i] = a[i + 1] / a[i];
  for (int i = n; i >= 1; i -- )
  {
    xx[i] = x / a[i];
    x %= a[i];
  }
  dp[1][0] = 1;
  if (xx[1]) dp[1][1] = 1;
  for (int i = 1; i < n; i ++ )
  {
    dp[i + 1][0] += dp[i][0];
    dp[i + 1][1] += dp[i][1];
    if (xx[i + 1]) dp[i + 1][1] += dp[i][0];
    if (xx[i + 1] + 1 != mx[i + 1]) dp[i + 1][0] += dp[i][1];
  }
  cout << dp[n][0] << endl;
  return 0;
}

E - Akari

暴力模拟

#include <bits/stdc++.h>
using namespace std;
const int N = 1505;
int n, m;
int g[N][N];
bool st[N][N];
bool check(int x, int y)
{
  if (g[x][y] == 1) return false;
  if (g[x][y] == -1) return false;
  if (x == 0 || x > n || y == 0 || y > m) return false;
  return true;
}
int main()
{
  int A, B;
  cin >> n >> m >> A >> B;
  vector<pair<int, int>> v;
  while (A -- )
  {
    int x, y; scanf("%d%d", &x, &y);
    g[x][y] = 1;
    v.push_back({x, y});
  }
  sort(v.begin(), v.end());
  while (B -- )
  {
    int x, y; scanf("%d%d", &x, &y);
    g[x][y] = -1;
  }

  for (int i = 0; i < v.size(); i ++ )
  {
    int x = v[i].first, y = v[i].second;
    st[x][y] = true;
    int a = x + 1, b = y;
    while (check(a, b)) st[a ++ ][b] = true;
    a = x, b = y + 1;
    while (check(a, b)) st[a][b ++ ] = true;
    a = x - 1, b = y;
    while (check(a, b)) st[a --][b] = true;
    a = x, b = y - 1;
    while (check(a, b)) st[a][b -- ] = true;
  }
  int ans = 0;
  for (int i = 1; i <= n; i ++ )
    for (int j = 1; j <= m; j ++ )
      if (st[i][j]) ans ++;
  cout << ans << endl;
  return 0;
}

D - Wandering

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200005;
int n;
ll a[N], s[N];
int main()
{
  cin >> n;
  ll mx = -1e18;
  ll sum = 0, ans = 0;
  ll tmp[N];
  ll val = 0;
  for (int i = 1; i <= n; i ++ )
  {
    scanf("%lld", &a[i]);
    s[i] = s[i - 1] + a[i]; 
    mx = max(s[i], mx);
    tmp[i] = mx;
    sum += s[i];
    ans = max(val + tmp[i], ans);
    val = sum;
  }
  cout << max(ans, (ll)0) << endl;
  return 0;
}

C - To 3

void work()
{
  LL n; cin >> n;
  int a[3] = {0};
  while (n)
  {
    int t = (n % 10) % 3;
    if (n % 10 != 0 && t == 0) a[0] ++;
    if (t) a[t] ++;
    // cout << n % 3 << endl;
    n /= 10;
  }
  int sum = a[1] + a[2] * 2;
  // cout << sum << endl;
  // cout << a[0] << " " << a[1] << " " << a[2] << endl;
  if (sum % 3 == 0)
    cout << 0 << endl;
  else if (sum % 3 == 1)
  {
    if (a[1] && (a[2] || a[0])) cout << 1 << endl;
    else if (a[2] > 1 && (a[0] || a[1])) cout << 2 << endl;
    else cout << -1 << endl;
  }
  else if (sum % 3 == 2)
  {
    // cout << a[0] << " " << a[1] << " " << a[2] << endl;
    if (a[2] && (a[0] || a[1])) cout << 1 << endl;
    else if (a[1] > 1 && (a[0] || a[2])) cout << 2 << endl;
    else cout << -1 << endl;
  }
}

B - Almost GCD

void work()
{
  int n; cin >> n;
  int p[1005] = {0};
  for (int i = 1; i <= n; i ++ )
  {
    int x; cin >> x;
    for (int j = 2; j <= x / j; j ++ )
      if (x % j == 0)
      {
        p[j] ++;
        while (x % j == 0)  x /= j;
      }
    if (x > 0) p[x] ++;
  }
  int ans = 0, cnt = 0;
  for (int i = 2; i <= 1000; i ++ ) if (p[i] > cnt) ans = i, cnt = p[i];
  cout << ans << endl;
}

A - twiblr

void work()
{
  int a, b; cin >> a >> b;
  cout << 2 * a + 100 - b << endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值