CodeDeluge Round 1 题解

A: A-B Problem

【知识点】数学、思维题

A − B = C < = > A = B + C A-B=C <=> A = B + C AB=C<=>A=B+C

A可能得取值一共有 R − 2 ∗ L + 1 R-2*L+1 R2L+1

对于这些 A A A的取值, B B B可能的取值有分别有 1 1 1 R − 2 ∗ L + 1 R-2*L+1 R2L+1种,AB确定,C就确定了

STD

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
typedef long long ll;
inline void solve()
{
    ll L, R;
    cin >> L >> R;
    if(L + L > R) {
        cout << 0 << endl;
    } else {
        //1+2+3+...+R-2*L+1
        cout << (R-L*2+1)*(R-L*2+2) / 2 << endl;
    }

}
int main()
{
    int t;
    cin >> t;
    while(t--)
        solve();
    return 0;
}

B: AB Problem

【知识点】思维题,不涉及算法

首先,可以肯定的事:对于一个字符串,如果开头是A,结尾是B,无论如何都没法将两头修改成一样的。

然后,对于一个长度为2的字符串,如果它本身不是回文的,也无法将它修改成回文。

接下来,我们考虑其他情况如何判断:

首先,除了开头是A,结尾是B,我们必定能用最多一次操作让两头边对称。

两头已经对称的几个位置就不用管,我们从第一对不对称的位置开始想:

假如是前AA后BA,我们从后面那个B的前一个位置开始一直往前推进,可以让两头的A中间全部包B;

前BA后BB,从前面这个A开始向后推进,可以让两个B中间全变成A;

前AB后AA,我们从后面第一个A的前一个位置开始一直往前推进,可以让两头的A中间全部包B;

前BB后AB,从前面第二个B开始向后推进,可以让两个B中间全变成A;

所以其余情况一定有可行解!

STD

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
typedef long long ll;

int main()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    if(s[0] == 'A' && s[n-1] == 'B' || s == "BA")
        puts("No");
    else puts("Yes");
    return 0;
}

C: Equation Recovery

本场签到题

【知识点】暴力

一共就9种情况,打表即可

STD

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using pii=pair<int,int>;
#define all(x) (x).begin(),(x).end()
constexpr ll MOD = 1e9+7;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);

    int s,a,b,c;
    cin>>s>>a>>b>>c;
    if(a+b+c==s){
        cout<<"+"<<" "<<"+"<<"\n";
    }else if(a+b-c==s){
        cout<<"+"<<" "<<"-"<<"\n";
    }else if((a+b)*c==s){
        cout<<"+"<<" "<<"*"<<"\n";
    }else if(a-b-c==s){
        cout<<"-"<<" "<<"-"<<"\n";
    }else if(a-b+c==s){
        cout<<"-"<<" "<<"+"<<"\n";
    }else if((a-b)*c==s){
        cout<<"-"<<" "<<"*"<<"\n";
    }else if(a*b*c==s){
        cout<<"*"<<" "<<"*"<<"\n";
    }else if(a*b+c==s){
        cout<<"*"<<" "<<"+"<<"\n";
    }else if(a*b-c==s){
        cout<<"*"<<" "<<"-"<<"\n";
    }
    return 0;
}

D: 拼数字的果冻

【知识点】DP,完全背包板子题

这道题因为涉及到知识点,所以定位是本场兴趣赛的最难题

d p [ i ] dp[i] dp[i]表示数字总和为 i i i的背包最大能选的数字个数(即位数最大),跑一个完全背包即可

求出位数最大的情况后再倒序找到最大的方案

由于高位要越大越好,所以倒序找路径时需要9~0循环

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define pdd pair<double, double>
typedef long long ll;

int main()
{
    int n, m;
    cin >> n >> m;
    vector<int> a(10);
    int p[10] = {0,2,5,5,4,5,6,3,7,6};

    for(int i=1; i<=m; i++)
    {
        int x;
        cin >> x;
        a[x] = 1;
    }
    vector<int> dp(n+5, -1);
    dp[0] = 0;
    for(int i=1; i<=9; i++)
    if(a[i]) {
        for(int j=p[i]; j<=n; j++)
        dp[j] = max(dp[j], dp[j-p[i]] + 1);
    }
    int t = n;
    for(int i=9; i>=1; i--)
    if(a[i])
    {
        while(t >= p[i] && dp[t-p[i]]+1 == dp[t])
        {
            cout << i ;
            t -= p[i];
        }
    }
    return 0;
}

E: Simple Math Problem

【知识点】数学,dp

这道题的task1就是基础的组合数问题,公式 c ( n , a ) ∗ c ( n − a , b ) ∗ c ( n − a − b , c ) c(n,a)*c(n-a,b)*c(n-a-b,c) c(n,a)c(na,b)c(nab,c)

对于task2,使用的知识点是组合数学中的隔板法模型,因为所有的小球都一样,那么使每个盒子的小球个数不小于其编号数,就是先在每个盒子里放 盒子编号 − 1 盒子编号-1 盒子编号1 个球,最后再在剩余 r e m rem rem个小球内进行插板,也就是有 C ( r e m − 1 , n − 1 ) C(rem-1,n-1) C(rem1,n1)种方法

解法1:快速幂,逆元

由于最后得出的数据量很大,所以直接使用 n ! / ( m ! ∗ ( n − m ) ! ) n!/(m!*(n-m)!) n!/(m!(nm)!)最后取模这种方式求组合数是不行的,肯定会爆数据范围,而1e9+7是一个素数,所以我们可以通过求逆的方式化除法为乘法, a / b = a ∗ i n v ( b ) a/b=a*inv(b) a/b=ainv(b),根据费马小定理, a p − 1 ≡ 1 ( m o d ( p ) ) {a^{p-1}}\equiv{1(mod (p))} ap11(mod(p)),所以 i n v ( b ) ( m o d ( p ) ) ≡ b ( p − 2 ) ( m o d ( p ) ) inv(b)(mod(p))\equiv {b^{(p-2)}}(mod(p)) inv(b)(mod(p))b(p2)(mod(p)),所以我们可以通过快速幂的方法防爆+加速+取模求出逆元,并通过递推的方法求出组合数。

STD (改编自 Unk1ndled 的提交)

#include <stdio.h>
#define ll long long
#define mod 1000000007
ll qpow(ll x, ll n) {
    ll res = 1;
    while (n > 0) {
        if (n & 1) {
            res = (res * x) % mod;
        }
        x = (x * x) % mod;
        n >>= 1;
    }
    return res;
}

ll qmod(ll n) {
    return qpow(n, mod - 2);
}

ll C(ll n, ll k) {
    if (k > n - k) {
        k = n - k;
    }
    ll res = 1;
    for (ll i = 0; i < k; ++i) {
        res = (res * (n - i)) % mod;
        res = (res * qmod(i + 1)) % mod;
    }
    return res;
}
int main() {
    ll n, a, b, c, m;
    scanf("%lld %lld %lld %lld", &n, &a, &b, &c);
    ll ans1 = (C(n, a) * C(n - a, b) % mod) * C(n - a - b, c) % mod;
    printf("%lld\n", ans1);
    scanf("%lld%lld", &m, &n);
    for (int i = 1; i <= n; i++)
        m -= i - 1;
    ll ans2 = C(m - 1, n - 1);
    printf("%lld\n", ans2);
    return 0;
}

task 2 解法2:dp(这是我没想到的)

由于数据出水了,所以被学长用dp解法破解了orz,不过多一种解题方法也不是什么坏事

c++题解 by fexla

//
// Created by admin on 2023/11/26.
//
#include <bits/stdc++.h>

using namespace std;


typedef long long ll;
const int M = 1e9 + 7;
//取模类,可以实现自动取模
int normalize(int x) {
    return x < 0 ? (x + M) : (x >= M ? x - M : x);
}

ll pw(ll a, ll b) {
    a %= M;
    ll c = 1;
    while (b) {
        if(b & 1)c = c * a % M;
        a = a * a % M;
        b >>= 1;
    }
    return c;
}

const int Frac_N = 100;
ll frac_inv[Frac_N];

struct frac {
    ll num;

    frac(int x = 0) : num(normalize(x)) {}

    frac(ll x) : num(normalize(x % M)) {}

    frac inv() const {
        if(num >= Frac_N)return pw(num, M - 2);
        return frac_inv[num] ? frac_inv[num] : (frac_inv[num] = pw(num, M - 2));
    }

    frac operator-() const { return M - num; }

    frac operator+(const frac f2) const { return (num + f2.num) % M; }

    frac operator-(const frac f2) const { return (num - f2.num + M) % M; }

    frac operator*(const frac f2) const { return (num * f2.num) % M; }

    frac operator/(const frac f2) const { return num * f2.inv().num % M; }

    frac &operator+=(const frac f2) { return *this = operator+(f2); }

    frac &operator-=(const frac f2) { return *this = operator-(f2); }

    frac &operator*=(const frac f2) { return *this = operator*(f2); }

    frac &operator/=(const frac f2) { return *this = operator/(f2); }

    friend std::istream &operator>>(std::istream &is, frac &f) {
        ll v;
        is >> v;
        f = frac(v);
        return is;
    }

    friend std::ostream &operator<<(std::ostream &os, const frac &f) { return os << f.num; }

    friend frac operator+(ll a, frac b) { return b + a; }

    friend frac operator-(ll a, frac b) { return frac(a) - b; }

    friend frac operator*(ll a, frac b) { return b * a; }

    friend frac operator/(ll a, frac b) { return frac(a) / b; }

};

vector<frac> j(200000);

void init() {
    j[0] = 1;
    for (int i = 1; i < 200000; ++i) {
        j[i] = j[i - 1] * i;
    }

}

frac C(frac a, frac b) {
    return j[a.num] / j[a.num - b.num] / j[b.num];
}

void solve1() {
    frac n, a, b, c;
    cin >> n >> a >> b >> c;
    cout << C(n, a) * C(n - a, b) * C(n - a - b, c) << '\n';
}

void solve2() {
    frac n, m;
    cin >> m >> n;
    m -= (1 + n) * n / 2;
    vector<vector<frac>> dp(n.num, vector<frac>(m.num + 1, 0));
    for (int i = 0; i <= m.num; ++i) {
        dp[0][i] = 1;
    }
    for (int i = 1; i < n.num; ++i) {
        frac sum = 0;
        for (int k = m.num; k >= 0; --k) {
            sum += dp[i - 1][k];
            dp[i][k] = sum;
        }
    }
    cout << dp[n.num - 1][0];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << setprecision(10) << fixed;
    init();
    solve1();
    solve2();
    return 0;
}

F: 懵哔 Automaton

【知识点】字符串,模拟

按照题意模拟即可,可以开一个计数器,到4的时候进入懵哔时间,循环变量直接+2因为在懵哔时间内字符串不会有任何改变,之后将计数器归零即可

STD

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define all(x) (x).begin(),(x).end()
#define allp(x,n) (x).begin()+(n),(x).end()
using ll=long long;
using pii=pair<int,int>;
constexpr ll MOD = 1e9+7;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	
	int n;
	cin>>n;
	int cnt=0;
	for(int i=1;i<=n;i++){
		cout<<"MB";
		cnt++;
		if(cnt==4){
			i+=2;
			cnt=0;
		}
	}
	return 0;
}

G: Reflector

【知识点】数学,模拟

很容易模拟出,由于是等分,所以只需要 ( A i + ( A j − A i ) ∗ ( k + 1 ) ) (A_i+(A_j-A_i)*(k+1)) (Ai+(AjAi)(k+1))% n n n即可,但是有一个坑点,就是题目并没有说明 A j A_j Aj一定会大于 A i A_i Ai,因此最后的结果有可能是负数,所以你需要对于负数情况再加上 n ∗ k n*k nk使其变成对应的正数再% n n n即可,记得开long long

STD

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define all(x) (x).begin(),(x).end()
#define allp(x,n) (x).begin()+(n),(x).end()
#define ms(x,y) memset((x),(y),sizeof((x)))

using ll = long long;
using pii = pair<int,int>;
constexpr ll MOD = 1e9+7;

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

    ll st,ed,n,k;
    cin>>n>>st>>ed>>k;
    if(ed>=st){
        cout<<(st+(ed-st)*(k+1))%n;
    }else{
        cout<<(st+(ed-st)*(k+1)+n*k)%n;
    }
    return 0;
}
  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸦羽FadingRaven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值