2023牛客寒假算法基础集训营2

第二场相对第一场还行,出的题感觉都不错。

A题:

Tokitsukaze and a+b=n (easy)

做法:暴力遍历一下就行,代码如下:

/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
void solve()
{
    int n, l, r, a, b;
    cin >> n >> l >> r >> a >> b;
    int ans = 0;
    for (int i = l; i <= r; i++)
    {
        int j = n - i;
        if (j >= a && j <= b)
            ans++;
    }
    cout << ans << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

B题:

Tokitsukaze and a+b=n (medium)

做法:推公式 O ( 1 ) O(1) O(1)做就行,代码如下:

for _ in range(int(input())):
    n=int(input())
    l,r=map(int,input().split())
    ll,rr=map(int,input().split())
    print(max(0,min(n-l,rr)-max(n-r,ll)+1))

J题:

Tokitsukaze and Sum of MxAb

做法:根据数学推导,最终式子就是
a n s = 2 n ∑ i = 1 n a b s ( a i ) ans=2n\sum _{i=1}^n abs(a_i) ans=2ni=1nabs(ai)

for _ in range(int(input())):
    n=int(input())
    l=[]
    sum=0;
    l=list(map(int,input().split()))
    for a in l:
        sum+=abs(a)
    print(sum*n*2)

D题:

Tokitsukaze and a+b=n (hard)

做法:是一道贪心加树的DFS,从下往上看,越下面的节点会被算法的越多,例如自己作为根节点会被算一次,父亲节点作为根节点会被算一次,爷爷节点作为根还会被算一次,以此类推,所以要越深的节点值越大,总价值就会更大,代码如下:

/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;

const int N = 2e5 + 10;
int n, fa[N];
vector<int> g[N];
ll w[N], dep[N];
void dfs(int now, int d)
{
    dep[now] = d;
    for (auto to : g[now])
    {
        dfs(to, d + 1);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    for (int i = 2; i <= n; i++)
    {
        cin >> fa[i];
        g[fa[i]].push_back(i);
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i];
    }
    dfs(1, 1);
    sort(w + 1, w + n + 1);
    sort(dep + 1, dep + n + 1);
    ll ans = 0;
    for (int i = 1; i <= n; i++)
    {
        ans += dep[i] * w[i];
    }
    cout << ans << endl;
    return 0;
}

C题:

Tokitsukaze and a+b=n (hard)

做法:这里两个区间要求不能是相同的区间,所以可以先算任意两个区间总的选法,再减去区间相同带来的方案数,就是最终答案。因为会区间修改,所以还需要用差分来维护,代码如下:

/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const ll mod = 998244353ll;
const int N = 2e5 + 10;
ll n, m;
ll f[N];
ll calc(ll l, ll r)
{
    ll x0 = max(n - r, l);
    ll x1 = min(n - l, r);
    ll dx = max(0ll, x1 - x0 + 1);
    return dx;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    ll ans = 0;
    cin >> n >> m;
    while (m--)
    {
        int l, r;
        cin >> l >> r;
        f[l]++, f[r + 1]--;
        ans = (ans - calc(l, r) + mod) % mod;
    }
    for (int i = 1; i < N; i++)
    {
        f[i] += f[i - 1];
    }
    for (int i = 1; i < N; i++)
    {
        int j = n - i;
        if (j > N || j <= 0)
            continue;
        ll num = f[i] * f[j] % mod;
        ans = (ans + num) % mod;
    }
    cout << ans << endl;
    return 0;
}

H题:

Tokitsukaze and K-Sequence

做法:假设数字 x x x 出现的次数为 c n t x cnt_x cntx

  • 如果 c n t x ≤ k cnt_x≤k cntxk,我们可以贪心地将每个 x x x 都分到某个子序列中,使得每个子序列要么只包含 1 个 x x x,要么不包含 x x x。所以此时数字 x x x 的贡献为 c n t x cnt_x cntx
  • 如果 c n t x > k cnt_x>k cntx>k,我们按照上面的方法分配完 k k k x x x,多出来的 x x x 必须分配到某个子序列中,导致那个子序列中,数字 x x x 没有贡献。所以此时数字 x x x 的贡献为 k − 1 k−1 k1

答案就是每种数字的贡献求和,代码如下:

/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int a[N], c[N];
void solve()
{
    memset(c, 0, sizeof c);
    int n;
    cin >> n;
    multiset<int> st;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        c[a[i]]++;
    }
    for (int i = 1; i <= 1e5; i++)
    {
        st.insert(c[i]);
    }
    ll lesum = 0, ge = ((int)st.size());
    for (int i = 1; i <= n; i++)
    {
        while (!st.empty() && (*st.begin()) <= i)
        {
            lesum += (ll)(*st.begin());
            st.erase(st.begin());
            ge--;
        }
        cout << lesum + ge * (i - 1) << endl;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

L题:

tokitsukaze and Three Integers

做法:还是注意到 i ! = j ! = k i!=j!=k i!=j!=k,可以先算出所有的答案,再减去有相等的时候的方案数,就是最终答案,这里 n n n较大,需要预处理,代码如下:

/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl '\n' //交互题删掉
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 5010;
int a[N], c[N], d[N][N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, p;
    cin >> n >> p;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        a[i] %= p;
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (i == j)
                continue;
            c[a[i] * a[j] % p]++;
            d[i][a[j] * a[i] % p] += 2;
        }
    }
    for (int i = 0; i < p; i++)
    {
        ll ans = 0;
        for (int k = 1; k <= n; k++)
        {
            ll tar = (i - a[k] + p) % p;
            ans += (c[tar] - d[k][tar]);
        }
        cout << ans << " ";
    }
    cout << endl;
    return 0;
}

F题:

Tokitsukaze and Gold Coins (easy)

做法:这个简单版本一开始没人做,其实直接暴力BFS就行,代码如下:

/*
coder:sunshine
school:njupt
*/
#include <bits/stdc++.h>
using namespace std;
#define endl 'n' //交互题删掉
typedef long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 5e5 + 10;
int n, k;
bool can[N][3];
int f[N][3];
int g[N][3];
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                can[i][j] = true;
                f[i][j] = g[i][j] = false;
            }
        }
        for (int i = 0, x, y; i < k; i++)
        {
            scanf("%d%d", &x, &y);
            can[x][y - 1] = !can[x][y - 1];
        }
        queue<pair<int, int>> que;
        f[1][0] = 1;
        que.emplace(1, 0);

        while (!que.empty())
        {
            auto [x, y] = que.front();
            que.pop();
            if (y < 2 && can[x][y + 1] && !f[x][y + 1])
            {
                f[x][y + 1] = 1;
                que.emplace(x, y + 1);
            }
            if (x < n && can[x + 1][y] && !f[x + 1][y])
            {
                f[x + 1][y] = 1;
                que.emplace(x + 1, y);
            }
        }
        g[n][2] = 1;
        que.emplace(n, 2);
        while (!que.empty())
        {
            auto [x, y] = que.front();
            que.pop();
            if (y > 0 && can[x][y - 1] && !g[x][y - 1])
            {
                g[x][y - 1] = 1;
                que.emplace(x, y - 1);
            }
            if (x > 0 && can[x - 1][y] && !g[x - 1][y])
            {
                g[x - 1][y] = 1;
                que.emplace(x - 1, y);
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if (f[i][j] && g[i][j] && !(i == 1 && j == 0))
                {
                    ans++;
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值