Codeforces Round #697 (Div. 3 D-G)

20 篇文章 1 订阅
10 篇文章 0 订阅

Problem - D - Codeforces

        (1)题目大意

                给你一个a数组表示内存大小,b数组表示方便度,问你要释放m内存后,剩余的方便度最大是多少。

        (2)解题思路

                明显的贪心思路是,我们按从大打到小排序方便度为1和为2的内存大小,然后预处理出为1和为2的方便度的数组的前缀和,然后我们枚举取多少个1,二分出还需要多少个2,然后答案取min,但是可能没有方便度为1的,所以我们还需要枚举单独取多少个2能达到m内存,再取min即可。

        (3)代码实现

// Problem: D. Cleaning the Phone
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/D
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
PII p[N];
int n, m;
void solve()
{
    cin >> n >> m;
    ll tot = 0, ans = INT_MAX;
    for (int i = 1; i <= n; i++)
    {
        cin >> p[i].fi;
        tot += p[i].fi;
    }
    vector<ll> v1, v2;
    vector<ll> s1, s2;
    for (int i = 1; i <= n; i++)
    {
        cin >> p[i].se;
        if (p[i].se == 1)
        {
            v1.push_back(p[i].fi);
        }
        else
        {
            v2.push_back(p[i].fi);
        }
    }
    if (tot < m)
    {
        cout << "-1" << endl;
        return;
    }
    sort(v1.rbegin(), v1.rend());
    sort(v2.rbegin(), v2.rend());
    ll pre1 = 0, pre2 = 0;
    for (int i = 0; i < v1.size(); i++)
    {
        pre1 += v1[i];
        s1.push_back(pre1);
    }
    for (int i = 0; i < v2.size(); i++)
    {
        pre2 += v2[i];
        s2.push_back(pre2);
    }
    for (int i = 0; i < s1.size(); i++)
    {
        ll val = s1[i], cnt = i + 1;
        if (val >= m)
        {
            ans = min(ans, cnt);
            continue;
        }
        auto it = lower_bound(s2.begin(), s2.end(), m - val);
        if (it == s2.end())
        {
            continue;
        }
        else
        {
            ans = min(ans, cnt + ((it - s2.begin()) + 1) * 2);
        }
    }
    for (int i = 0; i < s2.size(); i++)
    {
        ll val = s2[i], cnt = i + 1;
        if (val >= m)
        {
            ans = min(ans, 2 * cnt);
        }
    }
    cout << ans << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

Problem - E - Codeforces

         (1)题目大意

                给你一个n,k还有一个a数组,问你在长度为n种选k个的和最大值的方案数是多少

         (2)解题思路

                显然我们首先排序看多少位置和n-k+1这个位置的数相等,然后我们考虑设右边有r个,总共有tot个,那么答案就是C(tot,k)

        (3)代码实现

// Problem: E. Advertising Agency
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int mod = 1e9 + 7;
const int N = 5e3 + 10;
int a[N];
ll C[N][N];
void init()
{
    int n = 5000;
    C[0][0] = 1;
    for (int i = 1; i <= n; i++)
    {
        C[i][0] = 1;
        for (int j = 1; j <= i; j++)
        {
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
        }
    }
}
void solve()
{
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    sort(a + 1, a + 1 + n);
    int tot = 0, r = 0, idx = n - k;
    for (int j = idx + 1; j <= n; j++)
    {
        if (a[j] == a[idx])
        {
            r++;
        }
        else
        {
            break;
        }
    }
    tot = r + 1;
    for (int j = idx - 1; j >= 1; j--)
    {
        if (a[j] == a[idx])
        {
            tot++;
        }
        else
        {
            break;
        }
    }
    cout << C[tot][r] << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    init();
    cin >> T;
    while (T--)
        solve();
    return 0;
}

Problem - F - Codeforces

        (1)题目大意

                给你两个只含01的矩阵a和b,问你是否能通过两个操作(无限次数)把a数组变成b数组,第一个操作是:选一个一行翻转,第二个操作是选择一列翻转。

         (2)解题思路

                我们可以把一行一列看成一个整体,如果A[i][j] != B[i][j],说明行或者列只能翻一个,否则A[i][j] = B[i][j]要么就是行和列都翻,或者都不翻,(要注意建反边)因此考虑2-SAT,跑出来若不矛盾,则说明有解。

        (3)代码实现

// Problem: F. Unusual Matrix
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/F
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 1e3 + 10;
struct Edge
{
    int nt, to;
} e[N * N * 4 + 10];
char A[N][N], B[N][N];
int he[N * 4 + 10], idx, dfn[N * 4 + 10], low[N * 4 + 10], tim, ins[N * 4 + 10], id[N * 4 + 10], cor;
int n, stk[N * 8], top = 0;
void add(int a, int b)
{
    e[idx] = {he[a], b};
    he[a] = idx++;
}
void tarjan(int now)
{
    dfn[now] = low[now] = ++tim;
    ins[now] = true, stk[++top] = now;
    for (int i = he[now]; ~i; i = e[i].nt)
    {
        int j = e[i].to;
        if (!dfn[j])
        {
            tarjan(j);
            low[now] = min(low[now], low[j]);
        }
        else if (ins[j])
        {
            low[now] = min(low[now], dfn[j]);
        }
    }
    if (low[now] == dfn[now])
    {
        cor++;
        int y;
        do
        {
            y = stk[top--];
            id[y] = cor;
            ins[y] = false;
        } while (y != now);
    }
}
void solve()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
    {
        scanf("%s", A[i]);
    }
    for (int i = 0; i < n; i++)
    {
        scanf("%s", B[i]);
    }
    top = 0, tim = 0, idx = 0, cor = 0;
    for (int i = 0; i <= 4 * n; i++)
    {
        he[i] = -1;
        dfn[i] = low[i] = ins[i] = id[i] = 0;
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (A[i - 1][j - 1] != B[i - 1][j - 1])
            {
                add(j + n * 3, i);
                add(i, j + n * 3);
                add(i + n, j + 2 * n);
                add(j + 2 * n, i + n);
            }
            else
            {
                add(i + n, j + 3 * n);
                add(j + n * 3, i + n);
                add(j + n * 2, i);
                add(i, j + n * 2);
            }
        }
    }
    for (int i = 1; i <= 4 * n; i++)
    {
        if (!dfn[i])
        {
            tarjan(i);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (id[i] == id[i + n])
        {
            puts("NO");
            return;
        }
    }
    for (int i = 2 * n + 1; i <= 3 * n; i++)
    {
        if (id[i] == id[i + n])
        {
            puts("NO");
            return;
        }
    }
    puts("YES");
}
int main()
{
    int T = 1;
    scanf("%d", &T);
    while (T--)
        solve();
    return 0;
}

Problem - G - Codeforces

        (1)题目大意

                给你一个数组A,问你最少删除多少个元素后,A中的元素都有倍数关系。

         (2)解题思路

                考虑埃筛思路,我们枚举每个数的倍数是否出现在这个数组中,如果出现了,那么可以直接建边,在建完边后,考虑用拓扑排序+dp处理出最大能包含多少个,然后枚举一遍dp取个最大的就可以了。

          (3)代码实现

// Problem: G. Strange Beauty
// Contest: Codeforces - Codeforces Round #697 (Div. 3)
// URL: https://codeforces.com/group/OpoojmNlwv/contest/1475/problem/G
// Memory Limit: 256 MB
// Time Limit: 5000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
int a[N], have[N], in[N], dp[N], vis[N];
vector<int> G[N];
void solve()
{
    int n;
    cin >> n;
    int ans = n - 1;
    for (int i = 1; i <= 2e5; i++)
    {
        vis[i] = dp[i] = in[i] = have[i] = 0;
        G[i].clear();
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        have[a[i]]++;
    }
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++)
    {
        if (a[i] == a[i - 1])
            continue;
        for (int j = a[i] + a[i]; j <= 2e5; j += a[i])
        {
            if (have[j])
            {
                in[j]++;
                G[a[i]].push_back(j);
            }
        }
    }
    queue<int> q;
    for (int i = 1; i <= n; i++)
    {
        dp[a[i]] = have[a[i]];
        ans = min(ans, n - dp[a[i]]);
        if (in[a[i]] == 0)
        {
            q.push(a[i]);
        }
    }
    while (q.size())
    {
        int v = q.front();
        q.pop();
        vis[v] = true;
        for (auto x : G[v])
        {
            dp[x] = max(dp[x], dp[v] + have[x]);
            if (!vis[x])
            {
                q.push(x);
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        ans = min(ans, n - dp[a[i]]);
    }
    cout << ans << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值