Codeforces Round #739 (Div. 3)(AK实况)

Codeforces Round #739 (Div. 3)

在这里插入图片描述

A. Dislike of Threes

找到第 k k k个既不是 3 3 3的倍数,个位数上也不是 3 3 3的数,也已预处理然后 O ( 1 ) O(1) O(1)输出,也可直接 f o r for for循环暴力。

#include <bits/stdc++.h>

using namespace std;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  vector<int> a;
  for (int i = 1; i <= 2000; i++) {
    if (i % 3 == 0 || i % 10 == 3) {
      continue;
    }
    a.push_back(i);
  }
  int T, n;
  cin >> T;
  while (T--) {
    cin >> n;
    cout << a[n - 1] << "\n";
  }
  return 0;
}

B. Who’s Opposite?

2 × n 2 \times n 2×n个数按照顺序构成一圈, i i i的对立是 i + n i + n i+n,给定两个对立的 a , b a, b a,b,求 c c c的对立是谁。

容易发现 a b s ( a − b ) = n abs(a - b) = n abs(ab)=n,所以只要判断 a , b , c a, b, c a,b,c是否合法 ≤ 2 × n \le 2 \times n 2×n,然后判断 c c c在前半圈还是后半圈即可。

#include <bits/stdc++.h>

using namespace std;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  int T;
  cin >> T;
  while (T--) {
    int a, b, c;
    cin >> a >> b >> c;
    if (a > b) {
      swap(a, b);
    }
    int haf = b - a;
    if (c > haf * 2 || a > haf * 2 || b > haf * 2) {
      puts("-1");
    }
    else {
      if (c > haf) {
        printf("%d\n", c - haf);
      }
      else {
        printf("%d\n", c + haf);
      }
    }
  }
  return 0;
}

C. Infinity Table

可以得到,第 i i i次书写,有 2 × i − 1 2 \times i - 1 2×i1个数字,所以直接模拟即可,复杂度 T k T \sqrt k Tk ,当然也可以预处理一下,然后二分 O ( k + T log ⁡ k ) O(\sqrt k + T \log k) O(k +Tlogk)

#include <bits/stdc++.h>

using namespace std;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  int T;
  cin >> T;
  while (T--) {
    int n;
    cin >> n;
    for (int i = 1; ; i++) {
      int cur = 2 * i - 1;
      if (n > cur) {
        n -= cur;
      }
      else {
        if (n <= i) {
          printf("%d %d\n", n, i);
        }
        else {
          n -= i;
          printf("%d %d\n", i, i - n);
        }
        break;
      }
    }
  }
  return 0;
}

D. Make a Power of Two

给定一个数字字符串,可以移走其中任意数字,或者在末尾添加任意数字,要求在最少的步骤将其变为 2 2 2的幂次。

考虑得到 2 60 2 ^{60} 260以内所有 2 2 2的幂次数字的字符串,让给定字符串在上面按照顺序匹配,

找到能匹配上的一个最大子序列,然后计算操作次数,不断取最小值即可,整体复杂度 O ( 60 × 10 × T ) O(60 \times 10 \times T) O(60×10×T)

#include <bits/stdc++.h>

using namespace std;

string a[60];

void init() {
  for (int i = 0; i < 60; i++) {
    long long cur = 1ll << i;
    while (cur) {
      a[i] += char(cur % 10 + '0');
      cur /= 10;
    }
    reverse(a[i].begin(), a[i].end());
  }
}

int f(string str) {
  int ans = 0x3f3f3f3f;
  for (int i = 0; i < 60; i++) {
    int sum = 0, p1 = 0, p2 = 0, n = str.size(), m = a[i].size();
    while (p1 < n && p2 < m) {
      if (str[p1] == a[i][p2]) {
        p1++, p2++, sum++;
      }
      else {
        p1++;
      }
    }
    ans = min(ans, n - sum + m - p2);
  }
  return ans;
}

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  init();
  int T;
  cin >> T;
  while (T--) {
    string str;
    cin >> str;
    cout << min(f(str), (int)str.size() + 1) << "\n";
  }
  return 0;
}

E. Polycarp and String Transformation

考虑对串从后往前开始做,不难得到删除字母的顺序,我们再对字母的个数统计一下,加入字母 c c c是在第 k k k次删除,总共出现了 x x x次,

那么我们可以得出字母 c c c在原串中出现的次数就是 x k \frac{x}{k} kx次,通过这个,我们可以统计出原串的长度,

然后再对原串 O ( 不 同 字 母 个 数 × l e n t h ) O(不同字母个数 \times lenth) O(×lenth),统计模拟一下即可得到一个新的串,然后与给定串对比一下是否一样即可。

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;

int num[30], vis[N], len, cnt, n;

char str[N];

bool judge(int len) {
  string s;
  for (int i = 1; i <= len; i++) {
    s += str[i];
  }
  string ans = s;
  for (int i = 1; i <= cnt; i++) {
    string cur = "";
    for (auto it : s) {
      if (vis[i] == it - 'a') {
        continue;
      }
      cur += it;
    }
    ans += cur;
    s = cur;
  }
  if (n != ans.size()) {
    return false;
  }
  for (int i = 1; i <= n; i++) {
    if (str[i] != ans[i - 1]) {
      return false;
    }
  }
  return true;
}

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  int T;
  scanf("%d", &T);
  while (T--) {
    scanf("%s", str + 1);
    n = strlen(str + 1);
    for (int i = n; i >= 1; i--) {
      num[str[i] - 'a']++;
      if (num[str[i] - 'a'] == 1) {
        vis[++cnt] = str[i] - 'a';
      }
    }
    len = 0;
    reverse(vis + 1, vis + 1 + cnt);
    for (int i = 1; i <= cnt; i++) {
      len += num[vis[i]] / i;
    }
    if (judge(len)) {
      for (int i = 1; i <= len; i++) {
        putchar(str[i]);
      }
      putchar(' ');
      for (int i = 1; i <= cnt; i++) {
        putchar(char(vis[i] + 'a'));
      }
      puts("");
    }
    else {
      puts("-1");
    }
    for (int i = 0; i < 26; i++) {
      num[i] = 0;
    }
    cnt = 0;
  }
  return 0;
}

F. Nearest Beautiful Number

e a s y   h a r d easy\ hard easy hard的做法都是一样的,考虑数位 d p dp dp

我们定义 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k],表示第 i i i位前已用数字的状态是 j j j,后面还剩下 k k k位不同的数字可用, j j j是一个最大值为 2 10 − 1 2 ^{10} - 1 2101的二进制数。

通过定义可以发现这个状态对于不同的给定的 K K K都是没有影响的,所以可以不用每次做都去 m e m s e t memset memset,直接 d p dp dp即可。

或者我们可以考虑定义 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k],表示第 i i i位前医用数字的状态是 j j j,总的可用的不同数位是 k k k,然后根据不同的 K K K去转移也可。

最后,对于给定的 n , K n, K n,K,我们先数位 d p dp dp得到 x ≤ n − 1 x \le n - 1 xn1,且最多有 K K K位不同的数字有多少个,然后二分数位 d p dp dp去检验答案。

整体复杂度 O ( T × 10 × log ⁡ n + 10 × 1024 × 10 ) O(T \times 10 \times \log n + 10 \times 1024 \times 10) O(T×10×logn+10×1024×10)

#include <bits/stdc++.h>

using namespace std;

int f[15][1050][15], p[15], tot, n, k;

int dfs(int pos, int cur, int last, int flag, int lim) {
  if (last < 0) {
    return 0;
  }
  if (!pos) {
    return !lim;
  }
  if (!flag && !lim && f[pos][cur][last] != -1) {
    return f[pos][cur][last];
  }
  int ans = 0, nex = flag ? p[pos] : 9;
  for (int i = 0; i <= nex; i++) {
    if (lim) {
      if (i == 0) {
        ans += dfs(pos - 1, cur, last, 0, 1);
      }
      else {
        int mins = cur >> i & 1 ? 0 : 1;
        ans += dfs(pos - 1, cur | (1 << i), last - mins, flag && i == nex, 0);
      }
    }
    else {
      int mins = cur >> i & 1 ? 0 : 1;
      ans += dfs(pos - 1, cur | (1 << i), last - mins, flag && i == nex, 0);
    }
  }
  if (!flag && !lim) {
    f[pos][cur][last] = ans;
  }
  return ans;
}

int calc(int x) {
  tot = 0;
  while (x) {
    p[++tot] = x % 10;
    x /= 10;
  }
  return dfs(tot, 0, k, 1, 1);
}

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  memset(f, -1, sizeof f);
  int T;
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d", &n, &k);
    int cur = calc(n - 1);
    int l = n, r = 2000000000;
    while (l < r) {
      int mid = 1ll * l + r >> 1;
      if (calc(mid) > cur) {
        r = mid;
      }
      else {
        l = mid + 1;
      }
    }
    printf("%d\n", l);
  }
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值