训练赛总结(老李题集)

1.老李截获了一份电报,电报由字符组成(可能含有空格),他希望在这些字符串中提取出有用的情报。

例如:a1b23c456d007890中可以提取出1, 23, 456, 7890共4个数字。

现在,他得到了一个长度高达1000的字符串,请你帮他提取出所有的数字。

输入

本题有多组数据。
输入一个字符串S。

输出

输出提取出的所有数字,相邻两个数字用一个空格隔开。

不包含数字的时候输出空行

注意,你输出的数不能含有前导0。

输入:
u1s1qs
1a2b3c4d5e006d
a1b23c456d007890
2333
kur1su
alan0233
输出:
1 1
1 2 3 4 5 6
1 23 456 7890
2333
1
233

思路:我刚开始想到的是字符串数组,然后就没然后了遇到数字就存下来,注意前导0(样例中要注意它得是个合法的数字)

如果还有别的思路可以在下方“拍我一下”(留言)

时间复杂度:O(n^2)

c++代码

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int nu(string s1)
{
	int x = 0;
	for(int i=0;i<s1.size();i++)x = x * 10 + (s1[i] - '0');
	return x;
}
int main()
{
	string s;
	while (cin >> s)
	{
		int i = 0, w = 0, j, count1 = 0;
		string a1[1000];
		for (i = 0; i <s.size(); i++)
		{
			if (s[i] >= '0' && s[i] <= '9')
			{
				string a;
				for (j = i; s[j] >= '0' && s[j] <= '9'; j++)a += s[j];
				i = j;
				a1[w++] = a;
			}
		}
		for (int i = 0; i < w; i++)
			cout << nu(a1[i]) << " ";
		cout << '\n';
	}
	return 0;
}

//这样做也是可以的
#include<iostream>
#include<cstring>
using namespace std;
int main(){
    string str;
    int flag;
    while(getline(cin,str)){
        flag = 0;
        for(size_t i = 0; i < str.size(); i++){
            // 为数字
            if(str[i] >= '0' && str[i] <= '9'){
                // 为0,且不为最后一位,前面也没有非0数字
                if(str[i] == '0' && flag !=2 && i != str.size() - 1 ){
                    // 先导0
                    flag = 1;
                }else{
                    // 数字
                    flag = 2;
                    cout<<str[i];
                }
            }else{
                // 全0
                if(flag == 1)cout<<0;
                // 数字后的第一个字符,输出空格
                if(flag != 0)cout<<" ";
                // 恢复状态
                flag = 0;
            }
        }
        // 换行
        cout<<endl;
    }
}

2.

描述

老李看和尚是个粗人,自己还认识几个大字。这不?就考起了和尚。老李给了和尚一个字符串,要求和尚写出这个字符串的全排列。字符串的串长不超过100。

输入

多组输入。每次输入一个字符串。

输出

每输入一次即输出该字符串的全排列。

每个字符用空格隔开。

输出的字典顺序为ASCII码先后顺序。

样例:
123 

输出:
1 2 3 
1 3 2 
2 1 3 
2 3 1 
3 1 2 
3 2 1 

思路一:dfs+枚举

c++代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n;
string s;
char st[N];
bool used[N];
void dfs(int u)
{
    if(u>=n)//可以输出答案
    {
        for(int i=0;i<n;i++)
        {
            printf("%c ",st[i]);
        }
        printf("\n");
        return ;
    }
    for(int i=0;i<n;i++)
    {
        if(!used[i])
        {
            st[u]=s[i];//标记
            used[i]=true;
            dfs(u+1);//枚举下一个
            st[u]='0';//恢复
            used[i]=false;
        }
    }
}
int main()
{
    while(cin>>s)
    {
        sort(s.begin(),s.end());//枚举之前要排序一下确保顺序从小到大
        n=s.size();
        dfs(0);
    }
    return 0;
}

思路二:next_permutation+枚举

概述与分析:
      STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation。首先我们必须了解什么是“下一个”排列组合,什么是“前一个”排列组合。考虑三个字符所组成的序列{a,b,c}。

       这个序列有六个可能的排列组合:abc,acb,bac,bca,cab,cba。这些排列组合根据less-than操作符做字典顺序(lexicographical)的排序。也就是说,abc名列第一,因为每一个元素都小于其后的元素。acb是次一个排列组合,因为它是固定了a(序列内最小元素)之后所做的新组合。

      同样道理,那些固定b(序列中次小元素)而做的排列组合,在次序上将先于那些固定c而做的排列组合。以bac和bca为例,bac在bca之前,因为次序ac小于序列ca。面对bca,我们可以说其前一个排列组合是bac,而其后一个排列组合是cab。序列abc没有“前一个”排列组合,cba没有“后一个”排列组合。
     next_permutation()会取得[first,last)所标示之序列的下一个排列组合,如果没有下一个排列组合,便返回false;否则返回true。这个算法有两个版本。其中常用的版本使用元素型别所提供的less-than操作符来决定下一个排列组合。

c++代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string line;
    while(cin>>line)
    {
      sort(line.begin(),line.end());//全排列
      for(int i=0;i<line.size();i++)
      cout<<line[i]<<" ";
      puts("");
      while(next_permutation(line.begin(),line.end()))
      {
       for(int i=0;i<line.size();i++)
         cout<<line[i]<<" ";
         puts("");
      }
    }
    return 0;
}

3.

描述

老李为了提高全军的射击准度,举行了一次射击比赛,用四个等级(铜,银,金,白金)来衡量士兵的准度,在比赛中表现突出的可以晋级。所有新的参赛者都从铜牌组开始,只要他们在比赛中取得完美的成绩,他们就会被提升到下一个更高的组别。甚至可以在同一个比赛中多次提升参与者。

告诉你比赛开始时的各个等级的人数和比赛结束后的各个等级的人数,求在这场比赛中银牌,金牌,白金各晋升了多少人。

输入

输入由四行组成,每行包含 0..1,000,000 范围内的两个整数。第一行指定了比赛前后的铜牌人数。

第二行指定了比赛前后的银牌人数。第三行指定了比赛前后的金牌参赛人数。最后一行指定了比赛前后的白金人数。

输出

请输出三行,每行包含一个整数。第一行应包含从铜牌提升到银牌的参赛人数。

第二行应包含从白银晋升为黄金的参与者数量。最后一行应该包含从黄金晋升到白金的参与者数量。

样例:
1 2
1 1
1 1
1 2
输出:
1
1
1

思路:

时间复杂度:O(n)

c++代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int bef[4],aft[4];
int main(){
	for(int i=0;i!=4;++i)cin>>bef[i]>>aft[i];
	cout<<aft[1]+aft[2]+aft[3]-bef[1]-bef[2]-bef[3]<<endl<<aft[2]+aft[3]-bef[2]-bef[3] 
    <<endl<<aft[3]-bef[3]<<endl;
	return 0;
}

Java代码 

import java.io.*;
import java.util.*;
public class Main {
    static int a[]=new int[100];
    static int b[]=new int[100];
    public static void main(String args[])  {
        Scanner cin = new Scanner(System.in);
        for(int i=0;i<4;i++)
        {
            b[i]=cin.nextInt();
            a[i]=cin.nextInt();
        }
        System.out.println(a[1]+a[2]+a[3]-b[1]-b[2]-b[3]);
        System.out.println(a[2]+a[3]-b[2]-b[3]);
        System.out.println(a[3]-b[3]);
        return ;
    }
}

4.

描述

老李和他的老朋友楚云飞一起玩游戏(难得不打仗),他们的初始积分都为1。

赢的人可以将自己的分数乘以 (K的平方),而输的人也能乘以K。

他们玩的太开心了,以至于忘了自己玩了多久,甚至 K 是多少和游戏进行的回合数 N 都忘了。

现在给出他们俩最终的积分a,b,请问是否存在正整数K、N满足这样的积分,判断他们的游戏结果是否可信。

输入

第一行输入一个整数T(表示样例个数)

接下来T组样例

每组样例一行,输入两个正整数a,b(0<a,b<=1e9)

输出

输出T行

一行输出一个样例对应的结果

若结果可信,输出 Yes

否则,输出 No

样例:
6
2 4
75 45
8 8
16 16
247 994
1000000000 1000000
输出:
Yes
Yes
Yes
No
No
Yes

思路:每一回合游戏都会乘以k^3  模拟

c++代码:

#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    int n;
    long long a,b;
    cin>>n;
    while(n--)
   {
        cin>>a>>b;
        long long t=cbrt(a*b);
        long long x=a/t;
        long long y=b/t;
        if((x*x*y==a)&&(x*y*y==b))//需要好好意会
            cout<<"Yes"<<endl;
        else
            cout<<"No"<<endl;
    }
    return 0;
}

5.

众所周知,老李在打仗的时候抢了楚云飞三个营的装备。云飞兄可没少上门讨要。老李只好耍起赖来,声称把装备都下发给了n个士兵,让楚云飞自己去要回来。阎王好见,小鬼难缠。士兵在楚云飞满足要求后才把装备给他。有n个人在x轴上,每个人的坐标是一个整数,楚云飞在轴上穿梭,交换的商品只有一种,每一个人都有对这种物资的需求或者供应,如果delta[i] 是正数,表示这个人要供应delta[i]的数量,如果是负数,表示这个人需要−delta[i]的物资,保证delta的和非负,一开始楚云飞在0位置,手里没有任何物资,每一秒他可以往左或者往右走1个单位的距离,如果他和一个人在同一个位置,就可以满足他的要求(该过程不花费时间),每笔交易的数量是由楚云飞决定的,当然他不能给出超过自己手里含有的物资数量,行走过程中楚云飞手里可以拿着任意多的物资,到了一个人的位置,也可以选择不与之交易,最终楚云飞需要满足以下两点

1:楚云飞必须满足所有人的需求

2:必须要在最后一个人的位置结束。

求最少需要花费多少时间。

输入

第一行输入一个整数n (1 ≤ n ≤ 300)

第二行输入n个元素pos[i]( 1 ≤ pos[i] ≤ 1050), 表示每个人的位置

第三行输入n个元素delta[i](-1050≤ delta[i] ≤ 1050)表示每个人的需求

保证pos单调递增,delta的和非负

输出

输出一个整数表示最少需要花费的时间

样例:
5
3 14 15 92 101
-3 2 3 -3 1
输出:
143;

思路:模拟+枚举

res代表当前物资状态,res+delta[i]代表下一个物资状态,ans代表花费时间

如果res<0,res+delta[i]>=0代表当前物质不足以满足当前需要,必须要添加物资,而下一个地点物资正好可以供应需要,我们需要填补前面的空缺物资,一来一回,路程和时间都要乘2;

如果res<0,res+delta[i]<0代表当前很需要物资,必须要添加物资,下一个地点物资不足以供应,就继续往前走;

如果res>=0,res+delta[i]<0代表当前物质足够了,但是下个地点需要很多,需要标记一下下一个地点的值,因为下个地点的物质非常稀缺;

时间复杂度:O(n)

c++代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+10;
int n,ans;
int pos[N],delta[N];
int main()
{
    cin>>n;
    for (int i = 1; i <= n; i ++ )cin>>pos[i];
    for (int i = 1; i <= n; i ++ )cin>>delta[i];
    int res=0,x=0;
    for (int i = 1; i <= n; i ++ )
    {
        if(res<0&&res+delta[i]>=0)ans+=(pos[i]-x)*2;
        if(res>=0&&res+delta[i]<0)x=pos[i];
        ans+=pos[i]-pos[i-1];
        res+=delta[i];
    }
    return cout<<ans,0;
}

6.

前方的战事吃紧,老李又有了新的计划,准备向旅长请示。老李和旅长的电报采用了一种密码加密,现在请你完成其中的一环。给出两个字符串A,B。找出B串首次在A串中出现的位置。

输入

多组输入。

每一组输入两个字符串A,B,字符串不包含空格且长度不会超过1000。

输出

输出一个数字,表是B串在A串第一次出现的位置下标。

如果不匹配则输出-1。

样例:
123
3
123
4
输出
2
-1

思路:KMP字符串匹配

时间复杂度:o(n^2)

c++代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10, M = 3e6 + 10;
int n, m;
char p[N], s[M];
int ne[N];

int main()
{
    std::ios::sync_with_stdio(false);
    while (cin >> s + 1 >> p + 1)
    {
        bool flag = true;
        int n = strlen(p + 1), m = strlen(s + 1);
        for (int i = 2, j = 0; i <= n; i++)
        {
            while (j && p[i] != p[j + 1])j = ne[j];
            if (p[i] == p[j + 1])j++;
            ne[i] = j;
        }
        for (int i = 1, j = 0; i <= m; i++)
        {
            while (j && s[i] != p[j + 1])j = ne[j];
            if (s[i] == p[j + 1])j++;
            if (j == n)
            {
                flag = false;
                printf("%d\n", i - n);
                break;
            }
        }
        if (flag)printf("-1\n");
    }
    return 0;
}

思路二:STL 方法

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

int main()
{
  std::ios::sync_with_stdio(false);
    string s1,s2;
    while(cin>>s1>>s2)
    {
        int index=s1.find(s2);
        if(index<=s1.size())
        cout<<index<<endl;
        else cout<<"-1"<<endl;
    }
    return 0;
}

7.

描述

两军交战到了白热化阶段了,敌人把坦克开出来了。身为黄埔军校培养出来的高级将领,楚云飞当然清楚如何应对,他让部下布下了反坦克阵。就是一种尖尖的塔型堆。

输入

多组输入。

每次输入两行。

第一行是塔组成的字符,第二行代表塔的高度。

输出

见样例。

输入:
*
4
输出:
    *
   * *
  * * *
 * * * *

时间复杂度:O(n^2)

c++代码

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

int main()
{
  std::ios::sync_with_stdio(false);
   char c;
   int num;
   while(cin>>c>>num)
   {
       for(int i=0;i<num;i++)
       {
            for(int j=i;j<num-1;j++)cout<<" ";
            for(int k=0;k<=i;k++) cout<<" "<<c;
            cout<<endl;
       }
   }
}

 Java代码

import java.io.*;
import java.util.*;
public class Main {
    public static void main(String args[])  {
        Scanner cin = new Scanner(System.in);
        while(cin.hasNext())
        {
            char c= cin.next().charAt(0);
            int num=cin.nextInt();
            for(int i=0;i<num;i++)
            {
              for(int j=i;j<num-1;j++)
              System.out.print(" ");
              for(int k=0;k<=i;k++) 
              System.out.print(" "+c);
              System.out.println();
            }
        }
        return ;
    }
}

8.

描述

老李虽然没上过学,但是还是会算数的,现在给老李几个数字,让老李判断一下大小。

输入

单组输入。

每输入若干个数据,数据的个数不会超过100个,每个数据不超过2的32次方。

每个数据用换行隔开。

输出

输出一行。

如果前面所有的数字的和比最后的数字小,请输出 <

如果前面所有的数字的和比最后的数字大,请输出 >

如果前面所有的数字的和与最后的数字相等,请输出 =

样例:
1 2 3
输出
=

时间复杂度:o(n)

c++代码

#include <bits/stdc++.h>

using namespace std;
double a[110],b[110];
int x=0;
char c;
int main()
{

     while(cin>>a[x])x++;
        for(int i=0; i<x; i++)
        {
            b[i]=a[i]+b[i-1];
        }

    if(b[x-2]==a[x-1])puts("=");
    else if(b[x-2]<a[x-1])puts("<");
    else puts(">");

    return 0;
}

9.

八路军和小日子过得不错的日本人在前线交战。双方都布下了地雷,八路军装备比较落后,所以他们布下的地雷比较小,用'o'表示,于此相对的敌人的地雷用'O'表示,两个小的雷可以产生一个大雷的威力,但不会直接爆炸,当两个大的雷放在附件时就会发生爆炸。老李是指挥官,现在他想知道一排里地雷的最后情况,作为老李的doge军师,你能算出来吗?
输入

多组输入。

每次输入一个字符串。串长小于100。

每组输入只由'O'和'o'组成。

输出

输出最后的结果。

样例:
ooooOOOoOoo
输出;
Oo

思路:模拟+枚举

时间复杂度:O(n)

c++代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5;
typedef long long ll;
stack<char> p;
int main()
{
    string s;
    while(cin>>s)
    { 
        char s1[N];int xx=0;
        for (int i = 0; i < s.size(); i ++ )
        {
            if(p.empty())p.push(s[i]);
            else
            {
                if(s[i]=='o'&&p.top()=='o')
                {
                    p.pop();
                    s[i]='O';
                    i--;
                }
                else if(s[i]=='O'&&p.top()=='O')p.pop();
                else p.push(s[i]);
            }
        }
       while(p.size())
       {
           s1[xx++]=p.top();
            p.pop();
       }
       for(int i=xx-1;i>=0;i--)
       printf("%c",s1[i]);
       printf("\n");
    }
    return 0;
}

总结:

总体上来讲,题目都不难,大部分是贪心+枚举

但是我之前做的时候,确实是不咋地,只做出了几道题😭😭

其实有些代码可以优化。对了,如果还有别的解题思路,欢迎下方留言😘😘

java代码等后续有时间再更

今天太晚了,有疑问欢迎在下方留言

嗷嗷嗷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值