2024.11.26 周二日常

2024.11.26 周二日常

  • Q1. 1200
    给定一数组k(代表n个人的倍率),设在每个人上投资为xi,若其胜利则获k*xi,最终一人胜利。问是否可以保证无论谁胜利,收益大于总投资的方案。(n<=20,k<=50)

  • Q2. 1300
    给定一数组,问最小的k使所有长度为k的区间按位或相等。

  • Q3. 1500
    给定一数组,定义MAD:数组中出现大于一次且最大的数。操作直到数组全为0:每次操作i:1->n a[i]=MAD{a[i]的前缀数组}。问所有操作前数组和的总和。

  • A1.
    解法1. 二分总投资s,若总投资为x,则x+1也可满足,呈单调性。检查:给每人合法的最小投资判断总投资sum<=x。找到最小合法s,进行分配。
    解法2. 投入1/ki可获1,需满足:求和1/ki<1 两边乘lcm。判断每人投资lcm/k[i]是否合法。

  • A2. 48mins 读错题硬控20min,st板子不完善
    二分加ST表:若x合法,则x+1一定合法,k属于[x,n]。每次检查使用ST表查询区间按位或依次判断。

  • A3. 补 抽象问题造样例引导思考 样例不全面导致思考不全面
    观察发现题吧?造一个好数据,模拟发现关键点:1.操作后数组单调不降 2.操作1次可能有单个元素段,操作2次即为多个连续相同元素子数组。3.然后每次操作就是向右平移,找一个好的计算方法也很重要:根据到n+1位置的距离计算每个元素出现的次数。

A1.

#include <bits/stdc++.h>
#define int long long //
#define endl '\n'     //
using namespace std;
#define bug(BUG) cout << "bug:# " << (BUG) << endl
#define bug2(BUG1, BUG2) cout << "bug:# " << (BUG1) << " " << (BUG2) << endl
#define bug3(BUG1, BUG2, BUG3) cout << "bug:# " << (BUG1) << ' ' << (BUG2) << ' ' << (BUG3) << endl
const int mod = 998244353;
const int N = 10 + 5e5;
void _();
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
        _();
    return 0;
}

//  给定一数组k(代表n个人的倍率),设在每个人上投资为xi,若其胜利则获k*xi,最终一人胜利。问是否可以保证无论谁胜利,收益大于总投资的方案。(n<=20,k<=50)
//  1. 二分总投资s,若总投资为x,则x+1也可满足,呈单调性。检查:给每人合法的最小投资判断总投资sum<=x。找到最小合法s,进行分配。
//  2. 投入1/ki可获1,需满足:求和1/ki<1 两边乘lcm。判断每人投资lcm/k[i]是否合法。

// 2.数学
void _()
{
    int n;
    cin >> n;
    vector<int> k(n);
    for (int &_k : k)
        cin >> _k;
    auto lcm = [](int a, int b)
    {
        return a / __gcd(a, b) * b;
    };
    int L = k.front();
    for (int i = 1; i < n; i++)
        L = lcm(L, k[i]);
    int s = 0;
    for (auto k : k)
        s += L / k;
    if (s >= L)
    {
        cout << -1 << endl;
        return;
    }
    for (auto k : k)
        cout << L / k << ' ';
    cout << endl;
}

// 1.二分
// void _()
// {
//     int n;
//     cin >> n;
//     vector<int> k(n);
//     for (int &_k : k)
//         cin >> _k;
//     int l = 0, r = 1e9 * n + 1;
//     auto ok = [&](int x)
//     {
//         int sum = 0;
//         for (int i = 0; i < n; i++)
//             sum += x / k[i] + 1;
//         return sum <= x;
//     };
//     while (r - l - 1)
//     {
//         int mid = l + r >> 1;
//         if (ok(mid))
//             r = mid;
//         else
//             l = mid;
//     }
//     if (ok(r))
//     {
//         for (int i = 0; i < n; i++)
//             cout << r / k[i] + 1 << ' ';
//         cout << endl;
//     }
//     else
//         cout << -1 << endl;
// }

A2.

#include <bits/stdc++.h>
#define int long long //
#define endl '\n'     // 交互/调试 关
using namespace std;
#define bug(BUG) cout << "bug:# " << (BUG) << endl
#define bug2(BUG1, BUG2) cout << "bug:# " << (BUG1) << " " << (BUG2) << endl
#define bug3(BUG1, BUG2, BUG3) cout << "bug:# " << (BUG1) << ' ' << (BUG2) << ' ' << (BUG3) << endl
void _();
signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--)
        _();
    return 0;
}

//  给定一数组,问最小的k使所有长度为k的区间按位或相等。
//  二分加ST表:若x合法,则x+1一定合法,k属于[x,n]。每次检查使用ST表查询区间按位或依次判断。
//  48min
void _()
{
    int n;
    cin >> n;
    vector<int> a(n + 1);
    vector<vector<int>> dp(n + 1, vector<int>(32)); // 内存超限 必要时关long long
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    // init
    for (int j = 0; j < 30; j++) // j 是每一层状态
        for (int i = 1; i <= n; i++)
        {
            if (i + (1 << j) - 1 > n)
                continue;
            if (!j)
                dp[i][j] = a[i];
            else
                dp[i][j] = dp[i][j - 1] | dp[i + (1 << j - 1)][j - 1];
        }

    // query
    auto ask = [&](int l, int r)
    {
        int k = log(r - l + 1) / log(2);
        return dp[l][k] | dp[r + 1 - (1 << k)][k];
    };

    auto ok = [&](int x)
    {
        int ans = 0;
        for (int i = 1; i + x - 1 <= n; i++)
        {
            auto re = ask(i, i + x - 1);
            if (i == 1)
                ans = re;
            else
            {
                if (re - ans)
                    return 0;
            }
        }
        return 1;
    };
    // bug(111);
    int l = 0, r = n;
    while (r - l - 1)
    {
        int mid = l + r >> 1;
        if (ok(mid))
            r = mid;
        else
            l = mid;
    }
    cout << r << endl;
}

A3.

#include <bits/stdc++.h>
#define int long long //
#define endl '\n'     // 交互/调试 关
using namespace std;
#define bug(BUG) cout << "bug:# " << (BUG) << endl
#define bug2(BUG1, BUG2) cout << "bug:# " << (BUG1) << " " << (BUG2) << endl
#define bug3(BUG1, BUG2, BUG3) cout << "bug:# " << (BUG1) << ' ' << (BUG2) << ' ' << (BUG3) << endl
void _();
signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--)
        _();
    return 0;
}
//  抽象问题造样例引导思考 样例不全面导致思考不全面
//  给定一数组,定义MAD:数组中出现大于一次且最大的数。操作直到数组全为0:每次操作i:1->n a[i]=MAD{a[i]的前缀数组}。问所有操作前数组和的总和。
//  观察发现题吧?造一个好数据,模拟发现关键点:1.操作后数组单调不降 2.操作1次可能有单个元素段,操作2次即为多个连续相同元素子数组。
//  3.然后每次操作就是向右平移,找一个好的计算方法也很重要:根据到n+1位置的距离计算每个元素出现的次数。
void _()
{
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    auto f = [&]()
    {
        int sum = 0, tmax = 0;
        map<int, int> cnt;
        for (int i = 1; i <= n; i++)
        {
            sum += a[i];
            cnt[a[i]]++;
            if (cnt[a[i]] > 1)
                tmax = max(tmax, a[i]);
            a[i] = tmax;
        }
        return sum;
    };
    int res = f() + f();
    for (int i = n; i; i--)
        res += a[i] * (n - i + 1);
    cout << res << endl;
}
// //  34mins-36mins-55mins-补
// void _()
// {
//     int n;
//     cin >> n;
//     int sum = 0;
//     vector<int> a(n + 1);
//     for (int i = 1; i <= n; i++)
//         cin >> a[i], sum += a[i];

//     int tmax = 0;
//     map<int, int> cnt;
//     map<int, int> ans_cnt;
//     for (int i = 1; i <= n; i++)
//     {
//         cnt[a[i]]++;
//         if (cnt[a[i]] > 1)
//             tmax = max(tmax, a[i]);
//         if (tmax)
//             ans_cnt[tmax]++;
//     }
//     vector<pair<int, int>> ans;
//     for (auto [x, ct] : ans_cnt)
//         ans.push_back({x, ct});
//     sort(ans.rbegin(), ans.rend());
//     int pre = 0, res = sum;
//     for (int i = 0; i < ans.size(); i++)
//     {
//         auto [x, k] = ans[i];
//         // bug2(x, k);
//         res += pre * x * k;
//         if (k - 1)
//             pre += k;
//         if (k == 1 && pre && i) // 坑点
//             continue;
//         res += x * k * (k + 1) >> 1;
//     }
//     // bug(tmax);
//     cout << res << endl;
// }
posted @   Jkke  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示