CF 451 div2 A - E 题解

时间:2022-12-30 11:49:13

传送门
// 因为各种原因, 有很多场cf没打了, 所以最近都在补cf,全程自己补, 只是少了比赛的紧张气氛而已.
A: 直接做, 判中点

void solve()
{
    int n;
    while(~scanf("%d",&n) ) {
        if (n % 10 <= 5) cout << n - n%10 << endl;
        else cout << n + (10 - n %10) << endl;
    }
}

B: 给你n, a, b; 问是否存在x,y 满足ax + by = n;
由于数据很小, 直接枚举可做

void solve()
{
    int n, a, b;
    while(cin >> n >> a >> b) {
        int flag = 0;
        for (int i = 0 ; i * a <= n ; i++) {
            int y = (n - i * a) / b;
            if (i*a + y*b == n) {
                flag = 1;
                cout << "YES" <<endl;
                cout << i << ' ' << y << endl;
                break;
            }
        }
        if (!flag) cout << "NO" << endl;
    }
}

C: 给定n个人的一些电话号码, 如果同一个人的两个电话号码x, y ,若 y 是 x 的后缀, 则y就不能要. 最后输出这些人以及它的电话号码
直接模拟做就可以了, 练手速

map<string, int>mp;
map<int, string>mp2;
set<string>s[25];
vector<string>ans[25];
bool ok(string a, string b) {
    int len = a.length() - b.length();
    if (len < 0 ) return false;
    return a.substr(len, b.length()) == b;
}
void solve()
{
    int n;
    while(cin >> n) {
        int cnt = 0; int k = 0;
        for (int i = 1 ; i <= n ; i++) {
            string name;
            cin >> name;
            if (!mp[name]) {
                mp[name] = ++cnt;
                mp2[cnt] = name;
            }
            int num; cin >> num;
            for (int j = 0 ; j < num ; j++) {
                string u;
                cin >> u;
                s[mp[name]].insert(u);
            }
        }
        for (int i = 1 ; i <= cnt ; i++) {
            for (auto j : s[i]) {
                int flag = 0;
                for (auto k : s[i]) {
                    if (j == k) continue;
                    if (ok(k, j)) {
                        flag = 1;
                        break;
                    }
                }
                if (!flag) ans[i].pb(j);
            }
        }
        cout << cnt << endl;
        for (int i = 1 ; i <= cnt ; i++) {
            cout << mp2[i] << ' ' << ans[i].size();
            for (int j = 0 ; j < ans[i].size() ; j++) {
                cout << ' ' << ans[i][j];
            }
            cout << endl;
        }
    }
}

D: Vitalya 设置了n个闹钟, 但是第二天她想一直睡, 如果在连续的m分钟里有至少k个闹钟响起, Vitalya 就会醒, 问至少要关闭多少个闹钟Vitalya 才不会醒. 注: 1 3 这两个闹钟相隔不到2分钟.(如样例4)

直接贪心 + 模拟过, 将每一个闹钟存起来, 只要达到了k个闹钟, 那么我们就判断下此时为pos的闹钟和第pos-k+1个闹钟的时间间隔与m的关系. 如果小于m, 说明此时加进去的闹钟不合理, 那么我们贪心的删掉它, ans++, size–, 重复次操作就可以.

AC Code

const int maxn = 2e5+5;
int a[maxn], b[maxn];
void solve()
{
    int n, m, k;
    while(cin >> n >> m >> k) {
        for (int i = 1 ; i <= n ; i++) {
            cin >> a[i];
        }
        sort(a+1, a+1+n);
        int ans = 0; int p = 0;
        for (int i = 1 ; i <= n ; i++) {
            b[++p] = a[i];
            if (p >= k) {
                if (b[p] - b[p-k+1] < m) {
                    ans++;
                    p--;
                }
            }
        }
        cout << ans << endl;
    }
}

E: 给定n(n为偶数)个整数, 每次操作可以向其中一个整数加1或减1, 问最少操作几次可以使得这n个整数中恰好有n/2个平方数和n/2个不是平方数

我们贪心的想, 首先把1-1e9的平方数存下来, 然后判定输入的每一个数是否是平方数而分成两堆并同时算出每一个数变成操作数最少的平方数所需要的最小贡献, 如果平方数的数更多, 那么我们直接对不是平方数贡献进行排序, 去小的那几个就是了, 如果不是平方数的数更多, 那么直接从大到小遍历平方数的集合即可, 0即贡献2, 否则贡献1.

AC Code

const int maxn = 3e5+5;
const int maxm = 2e5+5;
int squ[maxn], a[maxm], w[maxm];
int v1[maxm], v2[maxm];
void init() {
    for (int i = 1 ; i <= 31623 ; i++) {
        squ[i] = 1ll*i*i;
    }
}
bool cmp(int i, int j) {
    return w[i] < w[j];
}
void solve()
{
    init();
    int n;
    while(cin >> n) {
        int k1 = 0, k2 = 0;
        for (int i = 1 ; i <= n ; i++) {
            cin >> a[i];
            int pos1 = lower_bound(squ, squ+31623, a[i]) - squ;
            int pos2 = upper_bound(squ, squ+31623, a[i]) - squ;
            if (pos1 == pos2) {
                w[i] = min(squ[pos2] - a[i], a[i] - squ[pos2-1]);
                v1[++k1] = i;
            }
            else w[i] = 0, v2[++k2] = a[i];
        }
        if (k1 == k2) {
            cout << 0 << endl;
            continue;
        }
        ll ans = 0;
        if (k1 > k2) {
            sort(v1+1, v1+1+k1, cmp);
            for (int i = 1 ; i <= k1 - n/2 ; i++) ans += w[v1[i]];
        }
        else {
            sort(v2+1, v2+1+k2);
            for (int i = k2 ; i > n/2 ; i--) {
                if (v2[i] == 0) ans += 2;
                else ans++;
            }
        }
        cout << ans << endl;
    }
}