2023.1.13

A.Fill The Bag

https://codeforces.com/contest/1303/problem/D

Statement

给定一个正整数 \(n\)\(m\) 个数 \(a_i\),保证所有 \(a_i\) 都是 \(2\) 的整数次幂。询问是否存在一个长度为 \(m\) 的序列 \(x_i\),使得:

\[\sum _ {i = 1} ^ {m} \frac {a_i}{2 ^ {x_i}} = n \]

\(\sum _{i = 1} ^ {m} x_i\) 最小。若存在则输出 \(\sum _{i = 1} ^ {m} x_i\)

Solution

由于 \(a_i\)\(2\) 的整数次幂,则 \(\frac {a_i}{2 ^ {x_i}}\) 则可以看作是 \(n\) 的二进制表示。原问题可以转化为:是否可以通过已有的一些个 \(2\) 的整数次幂,“凑”出 \(n\) 的二进制表示。

大的数只能往小变,小的数可以拼凑成大的数。且由于要最小化 div次数,我们可以按位从低到高考虑。假设当前即将考虑第 \(i\) 位,我们可以先试着用 \(i - 1\)位的来凑第 \(i\) 位的。若凑不出来,那就用 \(i\) 后面的有的最小的来凑 \(i\)

Code

#include <bits/stdc++.h>
typedef long long ll;
const int N = 1e5 + 5;
using namespace std;

int T, m, a[N];
ll n, cnt[100];

int main() {
    ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	freopen("in","r", stdin);
    cin >> T;
    while (T--) {
        cin >> n >> m;
        ll sum = 0;
        for (int i = 1; i <= m; i++) {
            cin >> a[i];
            sum += a[i];
            int ex = log2(a[i]);
            cnt[ex]++;
        }
        if (sum < n) cout << "-1" << endl;
        else {
            ll ans = 0;
            for (int i = 0; i < 60; i++) {
                if ((n >> i) & 1) {
                    int pos = i;
                    while (!cnt[pos]) ++pos;
                    --cnt[pos];
                    while (pos > i) {
                        --pos;
                        cnt[pos]++;
                        ++ans;
                    }
                }
                cnt[i + 1] += cnt[i] / 2;
            }
            cout << ans << endl;
        }
        memset(cnt, 0, sizeof(cnt));
    }
	return 0;
}

B.Obtain The String

https://codeforces.com/contest/1295/problem/C

Statement

给定两个字符串 \(s\)\(t\),令 \(tt\) 为空串。定义一种操作:每次可以选择 \(s\) 的一个字串 \(ss\)(非连续也可以),并把 \(ss\) 加入 \(tt\) 的末尾。询问是否能使 \(tt = t\),若可以输出最小的操作次数。

Solution

定义 \(f_{i,c}\) 表示 \(s\) 中从 第 \(i\) 位开始的后缀串中字母 \(c\) 出现的最早位置。 从后往前扫一遍即可得到这个 \(f\)。结合贪心的思想,每一次新的操作从第一位往后跳即可,跳到末尾则进行下一次操作。

Code

#include <bits/stdc++.h>
const int INF = 1 << 30;
const int N = 2e5 + 5;
using namespace std;

int T, g[N][30];
char s[N], t[N];
set<char> ss;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    freopen("in","r", stdin);
    cin >> T;
    while (T--) {
        cin >> (s + 1) >> (t + 1);
        int lens = strlen(s + 1), lent = strlen(t + 1);
        for (int i = 1; i <= lens; i++) ss.insert(s[i]);
        bool flag = false;
        for (int i = 1; i <= lent; i++) {
            if (!ss.count(t[i])) {
                flag = true;
                break;
            }
        }
        ss.clear();
        if (flag) cout << "-1" << endl;
        else {
            for (int j = 1; j <= 26; j++) g[lens + 1][j] = INF;
            for (int i = lens; i >= 1; i--) {
                for (int j = 1; j <= 26; j++) g[i][j] = g[i + 1][j];
                g[i][s[i] - 'a' + 1] = i;
            }
            int pos = 1, now = 1, cnt = 0;
            bool sign = false;
            while (now <= lent) {
                if (g[pos][t[now] - 'a' + 1] == INF) {
                    cnt++;
                    pos = 1;
                    sign = false;
                }
                else pos = g[pos][t[now] - 'a' + 1] + 1, now++, sign = true;
                if (pos == lens + 1) {
                    cnt++;
                    pos = 1;
                    sign = false;
                }
            }
            if (sign) cnt++;
            cout << cnt << endl;
        }
    }
	return 0;
}
posted @ 2023-01-14 00:51  BeyondLimits  阅读(24)  评论(0编辑  收藏  举报