【XCPC】2023 JSCPC & National Invitational of CCPC (Hunan)——AFHIJK

2023 Jiangsu Collegiate Programming Contest, 2023 National Invitational of CCPC (Hunan), The 13th Xiangtan Collegiate Programming Contest

本蒟蒻该阶段应该顶多处理这几题了,希望以后还能补出更多的题!

I. Elevator

签到题

题面解读

一个电梯里有n个人,选择了m个不同的楼层,询问最多可能有多少人在同一楼层。

分析

显然,当其他 m − 1 m-1 m1 个人在选择其他楼层时,剩下那个楼层的人一定是最多的。

参考代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 5;
int n, m;

void solve()
{
    cin >> n >> m;
    cout << n - (m - 1) << "\n";
}
int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    int t = 1;
    cin >> t;
    while(t--) solve();
    return 0;
}

H.Neil’s Machine

题面解读

将字符串 S S S 转变成 T T T 需要的操作次数,每次操作是将字符串的后缀子串全部 + K +K +K,其中 1 < = K < = 25 1 <= K <= 25 1<=K<=25

分析

可以看出,每次操作必须先将前部分全部转为与目标串 T T T 一致;否则,如果先改后面再改前面,会使得改前部分时后缀部分再次被修改。
所以我们从前往后遍历即可,使用标记记录前方已经修改了多少,逐位比较当前是否已经被修改与目标串一致。如果根据前部分的修改,当前位置已经与目标串一致,则无需操作;否则,执行一次后缀修改。

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;

int n, arr[N], modify = 0, res = 0;
string s, t;

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> s >> t;
    int tag = -1;
    for(int i =0; i < n; ++i)
    {
        arr[i] = t[i] - s[i];
        if(tag == -1 && arr[i] != 0) tag = i;
    }
    if(tag == -1)
    {
        cout << 0 << endl; // 说明目标串与初始串完全相同
        return 0;
    }
    for(int i = tag; i < n; ++i)
    {
        int temp = (arr[i] % 26 + 26) % 26;
        if(temp == modify % 26) continue;
        res ++;
        modify += ((temp - modify) % 26 + 26) % 26; // 记录前面已经修改了多少
    }
    cout << res;
}

J.Similarity (Easy Version)

动态规划,最长公共子串

题面解读

对于每组测试数据,给出 n n n 个字符串,比较这 n n n 个字符串的最长公共子串的长度。

参考代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 55;
int n;
string str[N];

int check(string str1, string str2) 
{
    int len1 = str1.length(), len2 = str2.length();
    int start = 0, mx = 0;
    vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
    for(int i = 1;i<=len1;i++){
		for(int j = 1;j<=len2;j++){
			if(str1[i-1] == str2[j-1])
				dp[i][j] = dp[i-1][j-1] + 1;
			if(dp[i][j] > mx){
				mx = dp[i][j];
				start = i - mx;
			}
		}
	}
    // cout << str1.substr(start,mx) << "\n";
    return mx;
}

void solve()
{
    cin >> n;
    for(int i = 1; i <= n; ++i) cin >> str[i];
    int mx = 0;
    for(int i = 1; i <= n; ++i) 
        for(int j = i + 1; j <= n; ++j)
        {
            // 比较第i和j个
            mx = max(mx, check(str[i], str[j]));
        }
    cout << mx << "\n";
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    int t = 1;
    cin >> t;
    while(t--) solve();
    return 0;
}

K.Similarity (Hard Version)

构造题

题面解读

构造出 n n n 个长度为 k k k 的最长公共子串为 m m m 的字符串,每个字符串不能一样。

分析

首先,排除无法构造出来的情况。如果,最长公共子串长度为 0 0 0 且需要的个数大于26,或者最长的长度大于等于其本身的长度 k k k
第一个可以构造一个全为 a a a 的字符串,第二个构造一个与第一个相似度刚好为 m m m 的字符串,后面全跟 b b b

随后,构造最长公共子串为 1 1 1 的字符串。形如 a c a c , . . . , a z a z , b c b c , . . . , b z b z , . . . , y z y z acac,...,azaz,bcbc,...,bzbz, ...,yzyz acac,...,azaz,bcbc,...,bzbz,...,yzyz

参考代码

#include<bits/stdc++.h>
using namespace std;

int n, m, k;
string s1, s2, s;

void solve()
{
    cin >> n >> m >> k;
    if((m == 0 && n > 26) || m >= k)
    {
        cout << "No\n";
        return;
    }
    cout << "Yes\n";
    if(m == 0)
    {
        // 相似度为0,则按序输出即可全a,全b...即可
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < k; ++j)
            {
                cout << char('a' + i);
            }
            cout << "\n";
        }
        return;
    }
    for(int i = 1; i <= k; ++i) s1 += 'a';
    s2 = s1.substr(0, m);
    for(int i = m + 1; i <= k; ++i) s2 += 'b';
    cout << s1 << "\n" << s2 << "\n";
    // 构造一个abab...abab,这个不可采用
    // 按照之前构造,ab字段与上面相似度至少为2,如果m == 1,则不符合要求.现在需要构造一个相似度最多为1的字符串
    for(int i = 0; i < k; ++i) s += s1[i]; 
    for(int i = 1; i <= k; i += 2) s[i] = char(s1[i] + 1);
    // 构造形如acac,...,azaz,bcbc,...,yzyz的字符串
    int cnt = 3;
    while(cnt <= n)
    {
        if(s[1] == 'z')
        {
            for(int i = 1; i < k; i += 2) s[i] = s[0] + 1;
            for(int i = 0; i < k; i += 2) s[i] += 1;
        }
        for(int i = 1; i < k; i += 2) s[i] += 1;
        cout << s << "\n";
        cnt++;
    }
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    solve();
}

A.Today’s Word

题面解读

将一个字符串分成前后两部分,每次前半部分保持不动,将后部分执行一个next操作,中间插入一个操作前的字符串。询问执行了 1 0 100 10^{100} 10100 之后,长度为 m m m 的后缀字符串是什么。

分析

因为模拟的次数足够大,所以最后主要就是看next()处理的后缀字符串。
由于next操作是将字母+1,所以会是一个以26为周期的循环,我们先快速幂求一下 1 0 100 m o d 26 10^{100} mod 26 10100mod26 的结果为 16 16 16

参考代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 5;
ll ksm(ll a, ll b, ll mod)
{
    ll res = 1;
    while(b)
    {
        if(b & 1) res = (res * a) % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res % mod;
} // 10e100 % 26 = 16
int n, m;
string str;

string next(string s)
{
    string ret;
    for(int i = 0; i < s.length(); ++i)
        ret += ((char)('a' + (s[i] - 'a' + 1) % 26));
    return ret;
}

void solve()
{
    cin >> n >> m >> str;
    str = str.substr(str.length() / 2);
    int op = 0;
    while(str.length() < m) str = str + next(str), op++;
    str = str.substr(str.length() - m);
    op = (16 - op + 26) % 26; 
    while(op--) str = next(str);
    cout << str << "\n";
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    int t = 1;
    // cin >> t;
    while(t--) solve();
    return 0;
}

F. Timaeus

题面解读

总共有 A A A 个常规材料,每次可以将 B B B 个常规材料合成为一个高级材料,现在有两种buff,每次合成只能使用一个:

  • 每次可以合成出两个高级材料,概率为 P P P
  • 合成一个高级材料返还一个常规材料,概率为 Q Q Q

需要最大化合成出的高级材料的数量期望。

分析

此题考虑使用动态规划进行一个概率期望计算,线性判断使用到第 i i i 个常规材料时的最大期望数量。其中,通过状态转移方程,可以发现,当每次合成只消耗一个时,需要特判。

参考代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6 + 5;
int a, b;
double p, q, dp[N];

void solve()
{
    cin >> a >> b >> p >> q;
    p = p / 100, q = q / 100;
    for(int i = b; i <= a; ++i)
        if(b!=1) dp[i] = max(p * (dp[i - b] + 2) + (1 - p) * (dp[i - b] + 1), q * (dp[i - b + 1] + 1) + (1 - q) * (dp[i - b] + 1));
        else dp[i] = max(p * (dp[i - b] + 2) + (1 - p) * (dp[i - b] + 1), 1 / (1 - q) + dp[i - b]);
    printf("%.9lf\n", dp[a]);
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    int t = 1;
    // cin >> t;
    while(t--) solve();
    return 0;
}
  • 29
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值