工作室招新题解

题解

A B2045 晶晶赴约会 B2045 晶晶赴约会 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

奇数有课,偶数没课,7单判

AC代码

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n ;cin>>n;
    if(n % 2 && n != 7) cout << "NO"<<endl;//同时满足即可
    else cout <<"YES"<<endl;
    return 0;
}

B B2082 数字统计B2082 数字统计 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

从L 遍历到 R 使用to_string转为字符串,然后count来计数就行了

第一遍交的时候,从0开始遍历了。。。。。

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int l , r , cnt = 0;
    cin >> l >> r;
    for (int i = l ; i <= r ; i++){
        string s = to_string(i);
        cnt += count(s.begin() , s.end() , '2');//count, 第一个参数是要查询区间的起始位置,第二个是终点位置,因为字符串的每个字符都要判断,所以用迭代器了,第三个参量是要查询的字符
    }
    cout << cnt <<endl;
    return 0;
}

C B2140 二进制分类B2140 二进制分类 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

枚举每个数字,判断是否是A类数字,使用位运算判断每一位是否为1即可

不想在外部写函数了,正好在刷leetcode时看见了function的奇妙用法,顺便试试

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    //枚举每个数字
    int n , ans = 0;
    cin >> n;
    //Lambda + function 实现内部函数
    function<bool(int)> cnt = [](int x){
        int c = 0 , d = 0;//c记录 1 的个数, d记录0的个数
        while(x){
            if(x&1) c++;
            else d++;
            x>>=1;//移位  111 -> 011 -> 001 -> 000
        }
        return c > d;
    };
    for (int i = 1 ; i <= n ; i++){
        if(cnt(i)) ans++;
    }
    cout << ans << ' ' << n - ans <<endl;
    return 0;
}
​

D B2110 找第一个只出现一次的字符B2110 找第一个只出现一次的字符 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

将字符串中的每个字母的出现次数记录下来,再遍历一遍,找到第一个出现次数为1的字符

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
int cnt[26];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    string s ;
    cin >> s;
    //统计每个字母出现个数
    for (int i = 0 ; i < s.size() ; i++){
        cnt[s[i] - 'a'] ++;//减去字符'a'即可把26个小写字母映射到0~25这个下标中
    }
    for (int i = 0 ; i < s.size() ; i++){
        if (cnt[s[i] - 'a'] == 1){//找到第一个只出现一次的字母,输出
            cout << s[i] << endl;
            return 0;
        }
    }
    cout << "no" <<endl;//没找到输出no
    return 0;
}

E P1259 黑白棋子的移动P1259 黑白棋子的移动 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

观察规律,假设下标从1开始,那么下标为1 -- n*2 + 2,最后两个字符是空行

就是每一次都要交换空行的两个字符和相邻的两个不同的棋子(最后四组不同

双指针指向左边第一个要交换的和右边第一个要交换的字符

第一次交换的是{n-1,n} 和{2n-1,2n}

第二次{n-1,n}和{2n-2,2n-1}

以此类推,可以得到,左边交换的下标往左移1位和右边下标往左移2位是轮流的,那么就可以用一个cnt来记录次数,实现反复移动

但是当左界下标移动到4的时候,就不一样了,看不出来规律,直接按样例来进行移动下标了

感觉是这里面最难的了

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    //看实例:明显,每次都是再交换相邻的两个不通的黑白棋与空行
    //之后通过将空格换回到上一次之前的位置,能够再次得到一对相邻的黑白棋,重复交换即可得到答案
    int n ;
    cin >> n;
    vector<char> a(2*n + 3);
    function<void()> print = [&](){
        for (int i = 1 ; i <= 2*n +2 ; i ++){//下表为0的元素没有使用到
            cout << a[i] ;
        }
        cout << '\n';
        return ;
    };
    //初始化,前n个为o , n+1 到 2n为*,最后还有两个空行字符
    for (int i = 1 ; i <= 2*n + 3 ; i++){
        if(i <= n ) a[i] = 'o';
        else if (i <= 2*n) a[i] = '*';
        else a[i] = '-';
    }
    print();
    //左边该交换的第一个字符和右边该交换的第一个字符的下标
    int l = n ,r = 2*n + 1;
    int cnt = 0; //记录交换次数,来实现轮流处理l和r
    while(l>4){
        swap(a[l] , a[r]);
        swap(a[l + 1] , a[r + 1]);
        cnt ++;
        if(cnt % 2 == 0) l--;
        else r-=2;
        print(); 
    }
    //最后四个采用样例的处理
    swap(a[l] , a[r]);
    swap(a[l + 1] , a[r + 1]);
    print();
    r--;
    swap(a[l] , a[r]);
    swap(a[l + 1] , a[r + 1]);
    print();
    l-=2;
    swap(a[l] , a[r]);
    swap(a[l + 1] , a[r + 1]);
    print();
    r--;
    swap(a[l] , a[r]);
    swap(a[l + 1] , a[r + 1]);
    print();
    l--;
    swap(a[l] , a[r]);
    swap(a[l + 1] , a[r + 1]);
    print();
    return 0;
}
​

F P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

枚举P,Q统计结果,P,Q都是在x0--y0区间的

枚举P,通过最小公倍数计算出Q,验证是否满足最大公约数和做小公倍数的那个条件

注意到:c++的除法是向下取整的,所以要注意点

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
//递归实现欧几里得算法求最大公约数 
int gcd(int a , int b){
    return b ? gcd(b , a % b) :a;
}
//递归求最小公倍数
int lcm(int a,int b){
    return a*b/gcd(a,b);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    //枚举P,Q统计结果,P,Q都是在x0--y0区间的
    //枚举P,通过最小公倍数计算出Q,验证是否满足最大公约数那个条件
    int x , y , ans = 0 ,cnt = 0;
    cin >> x >> y;
    //枚举p的取值
    for (int p = x ; p <= y; p++){
        int q = y*x/p;//计算出q
        //注意到因为向下取整,所以q有可能不能与p满足最小公倍数的条件,所以都判断一边了
        if( gcd(p,q) == x &&lcm(p,q) == y) ans ++ ;
    }
    cout << ans <<endl;
    return 0;
}

G P1604 B进制星球P1604 B进制星球 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

首先:

  • 数据最长有2000位,所以要进行加法的话必须要用高精度算法

  • 当n大于10时要处理字母

  • 每一位计算时转化为10进制进行计算,而且不会爆int

  • 输出的时候要转化回去而且逆序输出

最开始没看见2000位

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    //首先:
    //输入中可能存在字符,所以采用读入字符串的方式来读取
    //将数字转化为十进制计算之后再转化回去就可以了
    //注意到刚好 26个大写字母都有可能用到
    //两千位要用高精度,而且也不能转为10进制算了
    //转换:16进制大于9的本分转换为十进制, x - 'A' + 10
    //      10转16  y + 'A' - 10
    ll n ,x = 0, y = 0 , len;
    string a,b;
    vector<char> A,B;
    cin >> n >> a >> b;
    function <vector<char> (vector<char> , vector<char>)> add = [&](vector<char> A ,vector<char> B){
        if(A.size()<B.size()) return add(B,A);
        vector<char> C;
        int t=0;
        //t用来记录每一个位置上的数据大小
        for(int i=0;i<A.size();i++){
            //将每位数字转化为10进制,最大也会是 15 + 15 = 30 不会
            if(A[i] >= 'A') t +=A[i] - 'A' + 10;
            else  t += A[i] - '0';
            if(i<B.size()){
                if(B[i] >= 'A') t+=B[i] - 'A' + 10;
                else t += B[i] - '0';
            } 
            int p = t % n;//当前位置上的数字
            if (p >= 10) C.push_back(p - 10 + 'A');//p>=10 说明是十进制以上了,要处理
            else C.push_back(p + '0');
            t/=n;//进位
        }
        if(t) C.push_back('1');//最后一个如果不等于0,说明还要进一个位
        return C;
    };
    //逆序存入,方便进行进位
    for(int i=a.size()-1;i>=0;i--){
        A.push_back(a[i]);
    }
    for(int i=b.size()-1;i>=0;i--){
        B.push_back(b[i]);
    }
    vector<char> C = add(A,B);
    //逆序存的所以要逆序输出
    for(int i=C.size()-1;i>=0;i--){
       cout << C[i];
    }
    return 0;
}
​

H P1060 [NOIP2006 普及组] 开心的金明P1060 [NOIP2006 普及组] 开心的金明 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:

  1. 01背包

    1. 状态定义:

      • dp[i][j] 表示 以i为下标(序号),的容量(价格)为j的情况下所能得到的最大值

    2. 状态转移:

      • 当前物品购入 :dp[i][j] = dp[i-1][j - v[i]] + v[i] *w[i]

        由前一个序号的状态进行转移,同时需要留出能够容纳当前物品价格的空间

      • 当前物品不购入: dp[i][j] = dp[i-1][j] 直接由前一个状态转移即可

      • 两者取最大

    3. 优化空间:注意到每一次转移都只用到了前一个状态,即不需要将每一个状态都保存

      所以可以压缩为一维DP

      dp[j] = max(dp[j] , dp[j - v[i]] + v[i] *w[i])

AC代码:

#include <bits/stdc++.h>
#define ll long long 
#define pii pair<int,int>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    //状态分析:dp[i][j] 第i个序号所对应的为j的价格能得到的价值
    //最大值
    //状态转移:dp[i][j] = max(dp[i][j]  , dp[i][j- v[i]] + w[i])
    //状态转移:dp[i][j] = max(dp[i - 1][j]  , dp[i - 1][j- v[i]] + w[i])
    //状态压缩,每次只用到 dp[i-1] 这个位置,所以用滚动数组 dp[j] = max(dp[j], dp[j - v[i]] + v[i] * w[i]); 
    ll n , m;//防止爆int 
    cin >> m >> n; // m 为价格, n为个数
    vector<ll> dp(m+1);// 价格容量为0 - m
    vector<ll> v(n + 1) , w(n + 1);
    for (int i = 1 ; i <= n ; i++){
        cin >> v[i] >> w[i] ;
    }
    ll ans = 0;
    for (int i = 1 ; i <= n ; i++){
        for (int j = m ; j >= v[i] ; j--){
            dp[j] = max(dp[j] , dp[j - v[i]] + w[i] * v[i]);
        }
    }
    cout << dp[m] <<endl;
    return 0;
}

给未来大一萌新看的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值