Contestant. Rank 761. Rating +41.

A. Rigged!

题意

给定 \(n\) 个人的臂力 \(s_i\) 和耐力 \(e_i\)。若比赛的杠铃重量为 \(w\),那么所有满足 \(s_i \geq w\) 的人都可以举起杠铃,且可以举起 \(e_i\) 次。

输出最小的 \(w\),使第一个玩家能举起的次数严格最多。

思路

显然,我们要做的就是,让耐力大于等于第一个玩家的人都举不起杠铃。

那么,我们统计耐力大于等于第一个玩家的所有玩家的力量最大值,然后判断最大值是否小于第一个玩家的力量即可。

如果满足,那么 \(w = s_1\),否则无解。

时间复杂度:\(O(n)\)

对应AC代码

#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"

#include chatgpt3_5

using namespace std;

//#define FLOATING_OCEAN

#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()

const int N = 1e6 + 10, M = 2e5 + 10, mod = 1e9 + 7, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);

void solve() {
    int n;
    cin >> n;
    vector<pii> a(n + 1);
    for(int i=1;i<=n;i++){
        cin >> a[i].fs >> a[i].sc;
    }
    int mx = 0;
    for(int i=2;i<=n;i++){
        if(a[i].sc >= a[1].sc){
            mx = max(mx, a[i].fs);
        }
    }
    if(mx >= a[1].fs) {
        cout << -1 << '\n';
        return;
    }
    cout << a[1].fs << '\n';
}

signed main() {
# ifdef FLOATING_OCEAN
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
# endif
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
//    init();
    int t = 1;
    cin >> t;
    while (t--) solve();
}

有点抽象的题面(

B. Chips on the Board

题意

给定一个 \(n \times n\) 的方阵,以及两个长为 \(n\) 的序列 \(a, b\)

现在,需要在方阵中标记若干点,使对于方阵的任意一个点 \((i, j)\),它的同一行或同一列至少有一个点被标记。

若标记点 \((i, j)\) 的代价为 \(a_i + b_j\),输出满足条件的最小代价和。

思路

考虑下面的问题:

选定若干行和若干列进行涂色,使最后整个方阵都涂上色的最小代价和。

那么显然,要么我们把行全都填满,要么我们把列全都填满。

在本题也是一样的,只是我们全都填满行后,还得考虑列的选择;对列也是一样的。

但是,因为我们可以任意选,从而我们一定会选最小的。

那么,最后问题的答案就是 \(\min(n \cdot a_{\min} + \sum b_i,~n \cdot b_{\min} + \sum a_i)\)

时间复杂度:\(O(n)\)

对应AC代码

#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"

#include chatgpt3_5

using namespace std;

//#define FLOATING_OCEAN

#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()

const int N = 1e6 + 10, M = 2e5 + 10, mod = 1e9 + 7, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);

void solve() {
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    int sum1 = 0, sum2 = 0;
    for(int i=0;i<n;i++) {
        cin >> a[i];
        sum1 += a[i];
    }
    for(int i=0;i<n;i++) {
        cin >> b[i];
        sum2 += b[i];
    }
    sum1 += *min_element(all(b)) * n, sum2 += *min_element(all(a)) * n;
    cout << min(sum1, sum2) << '\n';
}

signed main() {
# ifdef FLOATING_OCEAN
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
# endif
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
//    init();
    int t = 1;
    cin >> t;
    while (t--) solve();
}

有意思的思维,但题面还是有点(

C. Make it Alternating

题意

给定一个二进制字符串,定义一次操作为选定一个位置,并将其删除。

输出使字符串变为 \(0, 1\) 交替需要的最小操作数,以及对应的方案数。

思路

首先,前者很好算,我们只需进行 "去重" 即可:\(00110001 \rightarrow 0101\)

至于后者,我们先一块一块进行考虑。对于每一块,若长度为 \(cnt\),那么我们就需要在 \(cnt\) 中选 \(cnt - 1\) 个数进行删除,也就是 \(C_{cnt}^{cnt - 1} = C_{cnt}^1 = cnt\) 种组合方式。

其次,我们得到了方案的所有组合方式,但方案的执行是有先后顺序的,从而我们还得乘上一个全排列。

后者可以通过预处理阶乘实现。

时间复杂度:\(O(n)\)

对应AC代码

#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"

#include chatgpt3_5

using namespace std;

//#define FLOATING_OCEAN

#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, M = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);

int fact[N];

void init(){
    fact[0] = fact[1] = 1;
    for(int i=2;i<=2e5;i++) fact[i] = fact[i - 1] * i % mod;
}

void solve() {
    string s;
    cin >> s;
    s = s + " ";
    int ans = 0, cnt = 1;
    int tmp = 1;
    for(int i=1;i<s.size();i++){
        if(s[i] == s[i - 1]){
            tmp ++;
        }else{
            ans = (ans + tmp - 1) % mod;
            cnt = cnt * tmp % mod;
            tmp = 1;
        }
    }
    cnt = cnt * fact[ans] % mod;
    cout << ans << ' ' << cnt << '\n';
}

signed main() {
# ifdef FLOATING_OCEAN
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
# endif
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    init();
    int t = 1;
    cin >> t;
    while (t--) solve();
}

注意,不是对每一块求全排列然后乘起来

D. Sum of XOR Functions

题意

给定一个长为 \(n\) 的数组 \(a\),输出 \(\sum_{l=1}^{n} \sum _ {r=l}^{n} f(l, r) \cdot (r - l + 1)\),其中 \(f(l, r) = a_l \oplus a_{l+1} \oplus \ldots \oplus a_{r-1} \oplus a_r\)

思路

我们可以一位一位考虑本题,这样对异或具有交换律。

那么,问题就转化为了:给定一个二进制序列,输出所有 连续子序列的异或和与序列长度的乘积 的总和。

这是一个比较经典的问题,我们直接暴力枚举右端点,然后在枚举的过程中记录左端点的个数,满足最后整个序列的异或和为 \(1\),从而将区间的和变为每个点的值之和。

异或和的值取决于区间中 \(1\) 个数的奇偶性,那么我们不妨记录前 \(i\) 个数中 \(0\) 的个数,以及 \(1\) 的个数,然后在出现 \(1\) 的时候,交换 \(0, 1\) 的个数即可(可以理解为进行了一次翻转,原来不合法的变为了合法)。

最后,我们累加每一位的结果即可。

时间复杂度:\(O(64n)\)

对应AC代码

#define chatgpt3_5 "bits/stdc++.h"
#define chatgpt4 "bits/extc++.h"

#include chatgpt3_5

using namespace std;

//#define FLOATING_OCEAN

#define int long long
#define pii pair<int, int>
#define pipi pair<pii, pii>
#define tpi tuple<int, int, int>
#define fs first
#define sc second
#define pb emplace_back
#define ep emplace
#define rall(x) x.rbegin(),x.rend()
#define all(x) x.begin(),x.end()

const int N = 2e5 + 10, M = 2e5 + 10, mod = 998244353, inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9, PI = acos(-1);

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for(int i=1;i<=n;i++) cin >> a[i];
    int ans = 0;
    for(int i=60;i>=0;i--){
        int cnt0 = 0, cnt1 = 0;
        int pre0 = 0, pre1 = 0;
        for(int j=1;j<=n;j++){
            pre0 = (pre0 + cnt0) % mod, pre1 = (pre1 + cnt1) % mod;
            if(a[j] & (1ll << i)){
                ans = (ans + (pre0 + 1) * (1ll << i) % mod) % mod;
                swap(pre0, pre1), swap(cnt0, cnt1);
                cnt1 ++, pre1 ++;
            }else{
                ans = (ans + pre1 * (1ll << i) % mod) % mod;
                cnt0 ++, pre0 ++;
            }
        }
    }
    cout << ans << '\n';
}

signed main() {
# ifdef FLOATING_OCEAN
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
# endif
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
//    init();
    int t = 1;
//    cin >> t;
    while (t--) solve();
}

有意思的数学题(