爪哇周赛 Round 3

赛事链接

爪哇周赛 Round 3


A

题目:oj | 回声频段

思路:

题目保证凡是差值为 m 的倍数的强度会落入同一频段,因此频段编号等价于强度对 m 取余的值(即 a_i % m)。因此,遍历所有 a_i,统计每个余数出现的次数(用长度为 m 的数组或哈希表),最后取最大出现次数即为答案。

代码:

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;


void go(){
    int n, m;cin>>n>>m;
    map<int, int>cnt;
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        cnt[x%m]++;
    }

    int ans = 0;
    for(auto [num, c]:cnt){
        ans = max(ans, c);
    }

    cout<<ans;el;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int _=1;
    cin >>_;
    while(_--){
        go();
    }
    return 0;
}
//ncccpc

B

题目:oj | 什么,这题是1700!!?

思路:

首先我们可以发现如果c[1]=1或者c[n]=1,那么我们必定失败,因为我们不可能选择l=0,r=n,这样说明我们无法在1地区和n地区部署防御兵。

然后我们还可以发现如果对于一个地区如果它是最高的或者最低的,也就是他为高度为1或者高度为n,并且它的c[i]=1。

那么我们没法找到一组l和r,让他的高度夹在l高度和r高度中间,那么它就无法部署防御兵。

排除这2种情况,我们就一定可以防守成功了,我们首先找到最高的位置和最低的位置,假设最低的位置是j,最高的位置是k。

我们可以直接用5次操作,反正没有限制,然后我们假设位置是这样的。上面代表s,下面代表下标

0000000000000000000000

1######j######k######n

第一次操作我们可以选择j和k,这样j到k的地方就都变成1了,那么就变成

0000000011111100000000

1######j######k######n

第二次操作我们可以选择1和k,这样在左半部分中,高度大于位置1并且低于位置k的地方就都变成1了。

第三次操作我们可以选择1和j,这样在左半部分中,高度大于位置j并且低于位置1的地方就都变成1了。

这时你会发现通过操作二和操作三,你让左部分全变成1了也就是

0111111011111100000000

1######j######k######n

同样的操作我们在右半部分实现。

第四次操作我们可以选择k和n,这样在右半部分中,高度大于位置n并且低于位置k的地方就都变成1了。

第五次操作我们可以选择j和n,这样在右半部分中,高度大于位置j并且低于位置n的地方就都变成1了。

最后我们发现

0111111011111101111110

1######j######k######n

由于我们排除了最开始说的2种情况,所以这样的字符串s肯定能防守成功。

代码:

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll i,j,k,t,n,a[200005];
string s;
void go(){
    cin>>n;
    k=1;
    for(i=1;i<=n;i++){
        cin>>a[i];
    }
    cin>>s;
    s=" "+s;   //这里给s位置调整一下
    if(s[1]=='1'||s[n]=='1'){//如果中了第一种情况就输出-1
        cout<<-1<<'\n';
        return;
    }
    for(i=1;i<=n;i++){//检查有没有中第二种情况
        if(s[i]=='1'&&(a[i]==1||a[i]==n)){
            k=0;
        }
    }
    if(k==0){//如果中了第二种情况就输出-1
        cout<<-1<<'\n';
        return;
    }else{
        cout<<5<<'\n';
        for(i=1;i<=n;i++){
            if(a[i]==1){
                j=i;
            }
            if(a[i]==n){
                k=i;
            }
        }
        if(j>k){//保证j位置在左,k位置在右
            swap(j,k);
        }
        cout<<j<<' '<<k<<'\n';
        cout<<1<<' '<<k<<'\n';
        cout<<1<<' '<<j<<'\n';
        cout<<j<<' '<<n<<'\n';
        cout<<k<<' '<<n<<'\n';
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>t;
    while(t--){
        go();
    }
    return 0;
}

C

题目:oj | 量化密钥比对

思路:

读入两个字符串,分别以小数点分开两部分处理,整数部分去除前导0,小数部分去除后导0,再合在一起比较是否相同即可。

代码:

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;


pair<str, str> split_dot(str s){
    bool dot = 0;
    str f = "",e = "";
    for(char c:s){
        if(c=='.'){
            dot = 1;
            continue;
        }
        if(!dot){
            f += c;
        }else{
            e += c;
        }
    }
    return {f, e};
}

str cut_f0(str s){
    str ns = "";
    bool n0 = 0;
    for(char c:s){
        if(c !='0'){
            n0 = 1;
        }
        if(n0){
            ns += c;
        }
    }
    return (ns.empty()? "0":ns);
}

str cut_e0(str s){
    while (!s.empty() and s.back()=='0')
    {
        s.pop_back();
    }
    return (s.empty()? "0":s);
}

void go(){
    str a, b;
    cin>>a>>b;
    auto [fa, ea] = split_dot(a);
    auto [fb, eb] = split_dot(b);

    str sa = cut_f0(fa) + "." + cut_e0(ea);
    str sb = cut_f0(fb) + "." + cut_e0(eb);

    cout<< (sa==sb? "YES":"NO");el;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int _=1;
    cin >>_;
    while(_--){
        go();
    }
    return 0;
}

D

题目:oj | 神秘浮石矩阵

思路:

结论:对于题目中定义的操作,任意满足阶梯型的初始矩阵都必然在若干次操作后回到最初状态,因此答案恒为 YES

证明要点(构造唯一的逆操作,说明操作为双射):

  • 记一次操作为 f。若已知某次操作的结果矩阵 b,我们可以唯一地恢复操作前旋转后的矩阵 v:对每一列,将该列的非零元素(它们在 b 中一定位于列的底部)按从上到下的顺序取出并放回到该列的顶端(其余位置补零),即可还原 v。
  • 再将 v 逆时针旋转 90° 就能唯一恢复操作前的矩阵 a。于是对于任意结果 b,逆过程是确定且唯一的,说明 f 在全集合上可逆,即 f 是一个双射(排列)。
  • 在有限集合( n × n n \times n n×n 个格子的有效排列数有限)上,任何双射都是由若干个互不相交的有限循环组成。初始状态位于某个循环上,沿着 f 的迭代必然在循环长度步后回到初始状态。

因此对任意满足条件的输入,输出恒为 YES

代码:

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;

void go(){
    int n; cin >> n;
    //vector<vector<int>> a(n+1, vector<int>(n+1));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int x;cin>>x;
        }
    }

    cout<<"YES";el;
}


signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int _=1;
    //cin >>_;
    while(_--){
        go();
    }
    return 0;
}

E

题目:oj | 密室刻印修补

思路:

把长度为10的字符串视作26进制数(a=0...z=25)。

  1. 将字符串从高位到低位转成整数 value。
  2. 计算 value + K,若超过最大值 26^10−1 返回 -1。
  3. 否则把新值按26进制还原为10个字母并输出。
    注意使用64位整数避免溢出。

代码:

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;

str s;
int K;
void go(){
    int res = 0;
    int up = 0;
    for(int i=0;i<10;i++){
        res = res*26 + s[i]-'a';
        up = up*26 + 'z'-'a';
    }

    res += K;
    if(res> up){
        cout<<-1;el;re;
    }

    str ans = "";
    for(int i=9;i>=0;i--){
        int sum = powl(26, i);
        int j = 0;
        while (res >= sum)
        {
            res -= sum;
            j++;
        }
        ans += (j+'a');
        
    }

    cout<<ans;el;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int _=1;
    //cin >>_;
    while(cin>>s>>K){
        go();
    }
    return 0;
}

F

题目:oj | 星环工程的任务链系统

思路:

任务链数量 = m! \times C_{n}^{m}

也就是从 n 中选 m(组合),再对选出的 m 个任务任意排列(排列数)。

可化简为:\frac{n!}{(n-m)!}

步骤:

  • 预处理 fac[]ifac[]
  • 逆元需用 快速幂 :x^{-1} = x^{MOD-2} \mod MOD,当且仅当xMOD互质。
  • 公式使用:ans = fac[n] \times ifac[n-m] \mod MOD

代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;
const int64 MOD = 998244353;

// 快速幂求逆元
int64 mod_pow(int64 a, int64 e) {
    int64 r = 1;
    while (e) {
        if (e & 1) r = r * a % MOD;
        a = a * a % MOD;
        e >>= 1;
    }
    return r;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;

    vector<pair<int,int>> queries(T);
    int max_n = 0;

    for (int i = 0; i < T; ++i) {
        cin >> queries[i].first >> queries[i].second;
        max_n = max(max_n, queries[i].first);
    }

    // 最大 n 的 factorial + ifac 预处理
    vector<int64> fac(max_n + 1), ifac(max_n + 1);
    fac[0] = 1;
    for (int i = 1; i <= max_n; ++i) fac[i] = fac[i-1] * i % MOD;
    ifac[max_n] = mod_pow(fac[max_n], MOD - 2);       // n! 的逆元
    for (int i = max_n; i >= 1; --i) ifac[i-1] = ifac[i] * i % MOD;

    while (T--) {
        int n = queries[T].first;
        int m = queries[T].second;

        if (m > n) {
            cout << 0 << '\n';
            continue;
        }

        // ans = n! / (n-m)!  = fac[n] * ifac[n-m]
        int64 ans = fac[n] * ifac[n - m] % MOD;
        cout << ans << '\n';
    }

    return 0;
}

G

题目:oj | 火焰与铁蹄之路

思路:

排序取前k大的v求和即可。

代码:

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define dd double
#define str string
#define el cout << '\n'
#define re return
#define ff first
#define ss second
#define pll pair<int,int>
#define pdd pair<dd,dd>
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;

struct p{
    int t;
    int v;
};

void go(){
    int n,k;cin>>n>>k;
    vector<p>a(n);
    for(int i=0;i<n;i++){
        cin>>a[i].t>>a[i].v;
    }

    sort(all(a), [](p a1, p a2){
        return a1.v>a2.v;
    });

    int sum = 0;
    for(int i=0;i<k;i++){
        sum += a[i].v;
    }

    cout<<sum;el;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    int _=1;
    cin >>_;
    while(_--){
        go();
    }
    return 0;
}

H

题目:oj | gq的图书馆之旅 - 3

思路:

输出520

代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int main() {
    cout << "520";
    return 0;
}
相关推荐
十五年专注C++开发1 小时前
Mimalloc:一款高性能、低开销和线程安全的C++内存分配器
c++·内存分配·mimalloc
吃着火锅x唱着歌1 小时前
LeetCode 3623.统计梯形的数目 I
算法·leetcode·职场和发展
迷途之人不知返1 小时前
二叉树的链式结构
数据结构
纵有疾風起1 小时前
【C++—STL】红黑树底层封装与set/map模拟实现
开发语言·c++·经验分享·面试·开源·stl
不会c嘎嘎1 小时前
【数据结构】红黑树详解:从原理到C++实现
开发语言·数据结构
却道天凉_好个秋1 小时前
c++ shared_ptr与unique_ptr总结
c++
吃着火锅x唱着歌1 小时前
LeetCode 2364.统计坏数对的数目
数据结构·算法·leetcode
qq_336313932 小时前
java基础-set类集合进阶
java·算法
不知所云,2 小时前
4. vscode c++ 环境及工程搭建 clangd + mingw
c++·ide·vscode·开发环境·clangd