CSP-X——沙煜博补题

 一、总分数:
T1【称心如意 satisied.cpp】:100
T2【AC 万岁  acok.cpp】:100
T3【解救达达 rescue.cpp】:0
T4【整理文本 text .cpp】:0

二、比赛过程

第一题比较简单但需理解透了才能得分,因为与要注意:

假设序列第 i 位取值为 j ( j 的范围为 11 到 99),那么需要满足 N \% j==0,并且需要满足 ii 能整除 N/jN/j,即 i\%(N/j)==0,j 的取值应该尽量小

第二题也,只要注意最初字符串通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。

第三题通过题目我们可以知道,只要有足够多的 0 混入怪兽的食物,就可以击败怪兽,救出达达。如果数字的二进制中有两个及以上的 0 ,怪兽不会吃掉这个数字。

第四题为了使得文本可以在一页之内就打印成功,小可必须使得文本整理在 M 行之内。小可数出了文本中总共有 N 个单词,并且小可记录出来了每个单词的长度 \sumL 。整理出来的文本必须要满足行首为当前行的第一个单词,相邻的两个单词需至少由一个空格间隔。

三、比赛分析

T1【称心如意 satisied.cpp】

1、题目大意

小可有一个正数数字 N,然后想得到一个称心如意的序列 S 与之匹配,为N+1假设序列第i 位取值为 j ( j 的范围为 1 到 9),那么需要满足N%j==0,并且需要满足 i 能整除 N/j,即 i\%(N/j)==0满足条件2的基础上,j的取值应该尽量小若条件2不能满足,那么第i位输出一个 -

2、比赛中的思考

可以直接进行枚举每一个数字,然后再枚举 的范围(从1到9),判断是否符合条件。

3、解题思路

可以直接进行枚举每一个数字,然后再枚举 的范围(从1到9),判断是否符合条件。

4、AC代码

#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    string s;
    for(int i = 0; i <= n; i++){
        s += "-";
        for(int j = 1; j <= 9; j++){
            if(n % j == 0 && i % (n/j) == 0){
                s[i] = j + '0';
                break;
            }
        }
    }
    cout << s << endl;
    return 0;
}

T2【AC 万岁  acok】

1、题目大意字符串子序列指的是从最初字符串通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。例如,acfbdebcd都是abcdef的子序列,而cae并不是。计算ac作为字符串子序列出现的次数

2、比赛中的思考

3、解题思路

可以直接枚举字符串,每遇到一个字符a ,就找出其后面的 c 的数量进行累加,统计答案,但是这样的做法时间复杂度为O(n²), 数据下会超时。可以先通过后缀和统计字符 c 的数量,然后枚举字符串,每遇到字符 a ,然后统计当前字符后面的字符 c 的数量,累加ans。

4、AC代码

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
#define TIE ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e5 + 10, M = 1e5 + 10;
const double PI = acos(-1.0);
const double eps = 1e-6;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
string s;
int a[N], c[N];
int main() {
    TIE;
    cin >> s;
    int l = s.size();
    // 后缀和c的数量
    if (s[l - 1] == 'c')
        c[l - 1] = 1;
    for (int i = l - 1; i >= 0; i--) {
        if (s[i] == 'c')
            c[i] = 1;
        c[i] += c[i + 1];
    }
    int ans = 0;
    for (int i = 0; i < l; i++) {
        if (s[i] == 'a')
            ans += c[i];
    }
    cout << ans << endl;
    return 0;
}

T3【解救达达 rescue】

1、题目大意

只要有足够多的 0 混入怪兽的食物,就可以击败怪兽,救出达达。如果数字的二进制中有两个及以上的 0 ,怪兽不会吃掉这个数字。计算一下这个区间内有多少个数字会伤害到怪兽。

2、比赛中的思考

可以枚举每个数字,然后对每个数字进行数字拆分,然后找满足条件的数字。

3、解题思路

可以直接遍历64位1的二进制数异或对应位的1,判断得到的数是否在给定范围内

4、AC代码 

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
    long long a, b;
    cin >> a >> b;
    long long cnt = 0;
    for (int i = 1; i <= 63; i ++) {
        for (int j = 0; j < i - 1; j ++) {
            long long sum = (1ll << i) - 1 - (1ll << j);
            if (sum >= a && sum <= b){
                cnt ++;
            }
        }
    }
    cout << cnt;
    return 0;
}

T4【整理文本 text 】

1、题目大意

为了使得文本可以在一页之内就打印成功,小可必须使得文本整理在 M 行之内。小可数出了文本中总共有 N 个单词,并且小可记录出来了每个单词的长度 \sumL 。整理出来的文本必须要满足行首为当前行的第一个单词,相邻的两个单词需至少由一个空格间隔。输出对应的行宽值。

2、比赛中的思考

数据下,每行至少需要放一个单词,那么可以进行暴力枚举,最短的情况为最大单词的长度,最大的情况就是所有单词放置在一行,进行暴力枚举。

3、解题思路

枚举三盏灯的耗电量,计算出此时每个格子的亮度,算出每个格子当前亮度与需求亮度的差值,这个差值由第四盏灯来填补。即枚举好三盏灯之后,我们可以 O(1) 算出第四盏灯的最低耗电量。
时间复杂度:O(n³)。

4、AC代码

 #include<bits/stdc++.h>
 #define N 220000
 using namespace std;
 long long a[N]={},m=0,mx=0,n=0;
 bool calc(long long num);
 int main(){
     scanf("%lld%lld",&n,&m);
     for(long long i=1;i<=n;i++){
         scanf("%lld",&a[i]);
         mx=max(mx,a[i]);
     }
     //输入,并找到单词长度最大值
     long long l=mx-1,r=1e15+1;
     //确定双端便边界,开始二分
     while(l+1<r){
         long long mid=(l+r)/2;
         if(calc(mid)==false){
             l=mid;
         }
         else{
             r=mid;
         }
     }
     printf("%lld\n",r);
     //输出答案r
     return 0;
     }
 bool calc(long long num){
     long long now=1,sum=-1;
     //now为当前用到第几行,sum表示用到第now行的第几列 //初始值是为了把第一个单词前面的空
     //格磨平
     for(long long i=1;i<=n;i++){
         if(sum+1+a[i]<=num){
             sum=sum+1+a[i];
             //当前行能在放就放
         }
         else{
             sum=a[i];
             now++;
             //放不了就另起一行
         }
     }
     if(sum==-1){
         now--;
     }
     //把初始值的误差过滤掉
     if(now<=m){
         return true;
     }
     //符合条件返回true
     return false;
     //否则返回false
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值