牛客周赛 Round 94

 A. 经典校招题

有这样一个经典的题目:一共有 n 阶台阶,现在你位于第 0 阶,每次可以向上走 1 阶或 2 阶。
现在,我们想要知道,最少需要走几次才能到达第 n 阶。 

解题思路:尽量每次走2, 不得已再走1 

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n; cin>>n;
    if(n&1) cout<<(n-1)/2+1;
    else cout<<n/2;
    return 0;
}

B. 小苯购物 

题目描述

小苯来到了超市,想要购买一件价格为 n 的商品,他有三张优惠券可以使用,具体来说:
 其中第 i 张优惠券的最低优惠价格为 ai(即目前的商品价格不低于 ai 元才可以使用),使用后可以减少此商品的价格 bi 元(但最多减到 0 元);
优惠券可以叠加使用,且每张优惠券要么用一次,要么不用。
现在小苯想知道,如果他以最优方式使用这三张优惠券,则最少可以花多少元买走这件商品。

输入描述:

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≦T≦104) 代表数据组数,每组测试数据描述如下: 
第一行一个正整数 n(1≦n≦109)。 
此后三行,第 i 行两个正整数 ai,bi(1≦ai,bi≦109),描述第 i 张优惠券。
输出描述:
对于每组测试数据,新起一行输出一个整数,表示在使用过优惠券后,此商品的最低价格。

解题思路:只有三张优惠卷, 直接全排列即可, 有顺序的使用这三张优惠卷

#include<bits/stdc++.h>
using namespace std;
using pii=pair<int,int>;
int main(){
    int t; cin>>t;
    while(t--){
        int n; cin>>n;
        vector<pii> a(3);
        for(int i=0;i<3;i++){
            cin>>a[i].first>>a[i].second;
        }
        int ans=n;
        vector<int> b; 
        for(int i=0;i<3;i++) b.push_back(i);
        do{
            int p=n;
            for(int x:b){
                int ai=a[x].first; int bi=a[x].second;
                if(p>=ai){
                    p=max(0,p-bi);
                }
            }
            ans=min(ans,p);
        }while(next_permutation(b.begin(),b.end()));
        cout<<ans<<endl;
    }
    return 0;
}

 C. 小苯的与三角形

题目描述

小苯给定了一个正整数 x,他对三角形很感兴趣,因此他想要你构造一个严格小于 x 的正整数 y(1≦y<x),使得 x,y,xand⁡yx, 这三个数字作为三角形的边长,可以构成一个非退化的三角形。
但小苯觉得,如果任意构造一个 y,那么问题有些过于简单了,因此他限制你要构造出最小的符合条件的 y。

【名词解释】
非退化三角形是指满足三条边长均大于 0 且任意两边之和均大于第三边的三角形。
本题中,and 用于表示按位与运算。如果您需要更多位运算相关的知识,可以参考 OI-Wiki的相关章节 或 百度百科的相关章节。

输入描述:

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≦T≦105) 代表数据组数,每组测试数据描述如下:
在一行上输入一个整数 x(2≦x≦2×109),表示小苯给定的初始数字。
输出描述:
对于每组测试数据,新起一行。如果无解,直接输出一个 −1;否则,输出一个正整数 y(1≦y<x),表示你构造的符合条件的最小 y。
我们可以证明,如果存在解的话,解是唯一的。

解题思路:题目中只给了你一个x, 让你找到最小的y, 满足x, y, x&y 满足三角形的最基本性质,

y<x, 首先x不能是2的幂次, 如果x是2的幂次, 说明它二进制数中只有一个1, eg: 4(100), 8(1000) , 此时x&y=0, 就不满足基本三角形的性质,    如果不是2的幂次, 让y等于最多二进制数最左侧1的大小, 然后x&y=y, 此时恰好满足基本基本三角形的性质   

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    cin>>t;
    while(t--) {
        int x;
        cin>>x;
        if((x&(x-1))==0){
            cout<<-1<<endl;
        }else{
            int b=31-__builtin_clz(x);  
            int y=1<<b;
            cout<<y<<endl;
        }
    }
    return 0;
}

D. 小苯的序列染色

题目描述

小苯有一个长度为 n 的字符串 s,一开始所有数字都是 0。下标从 1 开始。
现在,他可以使用一个字符串 t="110",来对 s 进行若干次「染色」操作,具体的,小苯可以做以下操作任意次:
从 s 中选择一个长度恰好为 3 的连续段 si,si+1,si+2(1≦i≦n−2),并将这三个字符依次赋值为: ‘1’,‘1’,‘0’;
换句话说,使用 ttt 对 sss 中长度为 333 的连续段进行覆盖,被覆盖的部分操作后会变成 “110"。注意:后来的操作会覆盖先前的操作。
现在小苯想知道,如果给定了一个最终的、仅由字符‘0’ 和 ‘1’ 构成的期望结果字符串 s,他想知道 s 能否通过任意次(可以为 0 次)「染色」操作变成 s′。请你帮帮他吧。

输入描述:

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≦T≦100)代表数据组数,每组测试数据描述如下:
第一行输入一个整数 n(1≦n≦2×105),表示序列 s 的长度。 
第二行输入一个长度为 n,仅由字符 ‘0’ 和 ‘1’ 构成的字符串 s′,表示小苯期望的最终结果。
除此之外,保证单个测试文件的 n 之和不超过2×10^5。

输出描述:
对于每组测试数据,新起一行。如果存在一种「染色」方案使得 s 可以变成 s′,则输出 YES,否则输出 NO。

解题思路:其实这题很简单,但是我赛时写了很长时间, 代码也写的很长,  你自己多画就会发现, 要想输出YES, 就要满足这两个性质;1. (首次出现)前两个1必须是连续的 2. s的最后一位必须是0 

正确代码: 

#include<bits/stdc++.h>
using namespace std;
int main(){
    int t; cin>>t;
    while(t--){
        int n; cin>>n;
        string s; cin>>s;
        vector<int> p;
        //1. 先统计1的位置
        for(int i=0;i<n;i++){ 
            if(s[i]=='1'){
                p.push_back(i);
            }
        }
        if(p.empty()) { cout<<"YES"<<endl; continue; }
        if(n<=2){ cout<<"NO"<<endl; continue; }
        else{
            if(p.size()==1||s.back()=='1'){
                cout<<"NO"<<endl;
            }else if(p[1]==p[0]+1){
                cout<<"YES"<<endl;
            }else{
                cout<<"NO"<<endl;
            }
        }
        p.clear();
    }
    return 0;
}

赛时代码: 

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t;
    cin >> t;
    string m = "110";
    while (t--) {
        int n;
        cin >> n;
        string s;
        cin >> s;
        if (n < 3) {
            bool a= true;
            for (char c : s) {
                if (c == '1') {
                    a = false;
                    break;
                }
            }
            cout<<(a?"YES\n":"NO\n");
            continue;
        }
        vector<int> b(n, 0);
        vector<char> cur(n);
        for (int i = 0; i < n; i++) {
            cur[i] = s[i];
        }
        for (int i = 0; i + 2 < n; i++) {
            int cnt = 0;
            for (int j = 0; j < 3; j++) {
                if (cur[i + j] !=m[j]) {
                    cnt++;
                }
            }
            b[i] = cnt;
        }
        queue<int> q;
        vector<bool> c(n, false);
        for (int i = 0; i + 2 < n; i++) {
            if (b[i] == 0) {
                q.push(i);
                c[i] = true;
            }
        }
        while (!q.empty()) {
            int i = q.front();
            q.pop();
            bool f = false;
            for (int j = 0; j < 3; j++) {
                if (cur[i + j] != '#') {
                    f = true;
                    break;
                }
            }
            if (!f) continue; 
            for (int j = 0; j < 3; j++) {
                int p = i + j;
                if (cur[p] == '#') continue;
                char o_c=cur[p];
                cur[p] = '#';
                for (int k = p - 2; k <= p; k++) {
                    if (k < 0 || k + 2 >= n) continue;
                    int j2 = p - k; 
                    if (o_c != m[j2]) {
                        b[k]--;
                        if (b[k]==0&&!b[k]) {
                            q.push(k);
                            c[k] = true;
                        }
                    }
                }
            }
        }
        bool f=true;
        for (int i = 0; i < n; i++) {
            if (cur[i] == '1') {
                f = false;
                break;
            }
        }
        cout<<(f?"YES\n":"NO\n");
    }
    return 0;
}

E.  小苯的数字操作

题目描述

小苯有一个正整数 n,他可以对 n 做不超过 k 轮操作,每轮操作从以下两种中任选一种进行:
∙将 n 除以 2 并向下取整,即将 n 变为 ⌊n2⌋;
,∙将 n 乘上 2,即将 n 变为 n×2。
他想知道,如果他重复取出一个新的 n 进行操作,每一次操作轮数不超过 k 轮(可以为 0 轮),那么操作过程中总共会产生多少个不同的数字,请你帮他数一数吧。

输入描述:

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≦T≦104) 代表数据组数,每组测试数据描述如下:
在单独的一行输入两个空格分割的正整数 n,k(1≦n,k≦109),表示小苯拥有的数字、以及他最多对 n 进行操作的轮数。
输出描述:
对于每组测试数据,新起一行。输出一个整数,表示操作过程中总共会产生多少个不同的数字。

解题思路:常规dfs会超时, 使用使用一个哈希表 a来记录,其中第一个元素 b 表示从 n 到 v 需要除以2的次数,第二个元素 c 表示 v 的二进制表示中最低位的0的个数(即 __builtin_ctzll(v),也就是 v 的二进制中末尾的连续0的个数)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main(){
    int t;
    cin>>t;
    while(t--) {
        int n, k;
        cin>>n>>k;
        unordered_map<ll, pair<ll,ll>> a; 
        ll cur=n;
        ll d=0; 
        while(cur>0){
            ll z= __builtin_ctzll(cur);
            ll v=cur>>z; 
            if (!a.count(v)) {
                a[v]={d, z};
            }
            d++;
            cur>>=1; 
        }
        ll d_=d; 
        ll ans=0;
        for (auto&x : a) {
            ll v=x.first,b=x.second.first,c=x.second.second;
            if(b>k) continue;  
            ll r=k-b,s=c-r;
            if(s<0) s=0;
            ll e=c+r;
            ans+=(e-s+1);
        }
        if(k>=d_) {
            ans+=1;
        }
        cout<<ans<<endl;
    }
    return 0;
}


 F. 小苯的小球分组

题目描述

小苯有 n个小球,其中第 i 个小球的颜色为 ai​。从其中取出一些小球,组成一个小球集合 S。定义小球集合 f(S),表示将小球集合 S 分为若干组,满足以下所有条件的最少分组个数:
每组最多有 2 个球;
 组内有 2 个球的组,这 2 个球的颜色不同。
现在小苯希望你求出这 n 个小球的所有非空子集(按位置区分)所对应的 f 函数值之和。由于答案可能很大,请将答案对 998 244 353取模后输出。

输入描述:

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1≦T≦100)代表数据组数,每组测试数据描述如下: 
第一行输入一个整数 n(1≦n≦5000),表示小球的总个数。 
第二行输入 n 个整数 a1,a2,…,an(1≦ai≦109),表示每个小球的颜色。 

除此之外,保证单个测试文件的 n 之和不超过 5×10^3
输出描述:
对于每一组测试数据,新起一行。输出一个整数,表示所有子序列的 f 函数值之和。由于结果可能很大,请将答案对 998 244 353 取模后输出。

视频讲解: F_哔哩哔哩_bilibili

解题思路:我想明白再给你们讲吧,不是很懂....

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5010;
const int mod = 998244353;
int a[N];
int fact[N], infact[N];
int qmi(int a,int b){
    int r = 1;
    while(b){
        if(b & 1) r = r * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return r;
}

int C(int n,int k){
    if(k < 0 || k > n) return 0;
    return fact[n] * infact[k] % mod * infact[n-k] % mod;
}

void solve(){
    int n;
    cin >> n;
    map<int,int> mp;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
        mp[a[i]]++;
    }
    vector<int> vec;
    vec.reserve(mp.size());
    for(auto &kv: mp) vec.push_back(kv.second);
    sort(vec.begin(), vec.end(), greater<int>());
    int ans = 0;
    for(int i = 1; i <= n; i++){
        int t = (i + 1) / 2;  
        int res = 0;      

        for(int j = t+1; j <= i; j++){
            for(int cnt: vec){
                if(cnt < j) break;
                int ways = C(cnt, j) * C(n - cnt, i - j) % mod;
                res = (res + ways) % mod;
                ans = (ans + ways * j) % mod;
            }
        }
        int rest = (C(n,i) - res + mod) % mod;
        ans = (ans + rest * t) % mod;
    }

    cout << ans << "\n";
}
signed main(){
    fact[0] = infact[0] = 1;
    for(int i = 1; i < N; i++){
        fact[i] = fact[i-1] * i % mod;
        infact[i] = qmi(fact[i], mod-2);
    }
    int T;
    cin >> T;
    while(T--) solve();
    return 0;
}

感谢大家的点赞和关注,你们的支持是我创作的动力!

注:我是真不擅长思维题(其实什么也不擅长, 哈哈哈)

 

### 关于周赛 Round 80 的相关信息 目前并未找到具体针对周赛 Round 80 的官方题解或比赛详情文档。然而,基于以往的比赛模式和惯例[^1],可以推测出此类赛事通常包含若干算法题目,覆盖基础数据结构动态规划、贪心策略以及图论等领域。 #### 可能涉及的内容范围 1. **签到题 (A 题)** 这类题目一般较为简单,旨在测试选手的基础编程能力。例如简单的数学计算或者字符串处理问题。 2. **中级难度题 (B 到 D 题)** 中级难度的题目往往需要一定的算法设计能力和复杂度分析技巧。比如: - 动态规划优化问题; - 贪心算法的应用场景; - 图遍历与最短路径求解; 3. **高阶挑战题 (E 或更高)** 对于更复杂的题目,则可能涉及到高级的数据结构操作(如线段树、并查集)、组合数学推导或者其他领域内的难题解决方法。 以下是根据过往经验给出的一个假设性的例子来展示如何解答类似的竞赛问题: ```python def solve_example_problem(n, m): """ 假设这是一个关于矩阵填充的问题, 给定 n 行 m 列大小的空间,按照某种规则填充值。 参数: n -- 矩阵行数 m -- 矩阵列数 返回值: result_matrix -- 完成后的二维列表形式的结果矩阵 """ # 初始化结果矩阵为全零状态 result_matrix = [[0]*m for _ in range(n)] value_to_fill = 1 direction_changes = [(0,1),(1,0),(0,-1),(-1,0)] # 方向变化顺序:右->下->左->上 current_direction_index = 0 row,col=0,0 while True: try: if not(0<=row<n and 0<=col<m): raise IndexError() if result_matrix[row][col]==0: result_matrix[row][col]=value_to_fill value_to_fill+=1 next_row,next_col=row+direction_changes[current_direction_index%len(direction_changes)][0],\ col+direction_changes[current_direction_index%len(direction_changes)][1] if any([not(0<=next_row<n), not(0<=next_col<m), bool(result_matrix[next_row][next_col])]): current_direction_index +=1 else: row,col=next_row,next_col except Exception as e: break return result_matrix if __name__ == "__main__": test_result=solve_example_problem(4,5) for line in test_result: print(line) ``` 上述代码片段展示了如何通过模拟实现一个螺旋状填充整数值至指定尺寸矩形中的过程作为示范案例之一[^4]。 ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值