C++字符串处理专题

目录

      • 7-1 字符串排序
      • 7-2 删除重复字符
      • 7-3 统计字符出现次数
      • 7-4 IP地址转换
      • 7-5 英文单词排序
      • 7-6 藏尾诗
      • 7-7 删除字符串中的子串
          • 直接手动模拟会很折磨
          • 用string的find,结合erase或者replace会很舒适
      • 7-8 字符串的冒泡排序
      • 7-9 字符串循环左移
      • 7-10 说反话-加强版
      • 7-11 切分表达式——写个tokenizer吧
          • 一开始的思路是用个标记,标记上一个已经输出的类型是什么,一次来判断正负号是运算符还是符号,但是这样不知道有什么问题,反正样例是过去了,而如下的写法还更加简便,也通过了
      • 7-12 输出GPLT
      • 7-13 Left-pad
      • 7-14 A-B
      • 7-15 最长对称子串
      • 7-16 古风排版
          • 输出只能用两重循环,需要手动计算当前二维坐标映射到字符串中的一维坐标,同时要注意除法取整问题
      • 7-17 猜数字
      • 7-18 估值一亿的AI核心代码
      • 7-19 口罩发放
      • 7-20 凯撒密码
          • 坑点提示:char型变量范围-128到127,而'z'=122,计算偏移过程中可能会发生溢出,需要使用int型作为中间变量来过渡
      • 7-21 吉老师的回归

7-1 字符串排序

本题要求编写程序,读入5个字符串,按由小到大的顺序输出。

输入格式:
输入为由空格分隔的5个非空字符串,每个字符串不包括空格、制表符、换行符等空白字符,长度小于80。

输出格式:
按照以下格式输出排序后的结果:

After sorted:
每行一个字符串
输入样例:
red yellow blue black white
输出样例:
After sorted:
black
blue
red
white
yellow

#include 

using namespace std;

string s[10]; 

int main()
{
	for(int i=0;i<5;++i)cin>>s[i];
	sort(s,s+5);
	cout<<"After sorted:"<<endl;
	for(int i=0;i<5;++i)cout<<s[i]<<endl; 
	return 0;
}

7-2 删除重复字符

本题要求编写程序,将给定字符串去掉重复的字符后,按照字符ASCII码顺序从小到大排序后输出。

输入格式:
输入是一个以回车结束的非空字符串(少于80个字符)。

输出格式:
输出去重排序后的结果字符串。

输入样例:
ad2f3adjfeainzzzv
输出样例:
23adefijnvz

#include 

using namespace std;

string s;
char ans[100];
bool st[300];
int p=0;

int main()
{
	getline(cin,s);
	for(int i=0;i<s.size();++i)
	{
		if(st[s[i]])continue;
		ans[p++]=s[i];
		st[s[i]]=true;
	}
	sort(ans,ans+p);
	cout<<ans;
	return 0;
}

7-3 统计字符出现次数

本题要求编写程序,统计并输出某给定字符在给定字符串中出现的次数。

输入格式:
输入第一行给出一个以回车结束的字符串(少于80个字符);第二行输入一个字符。

输出格式:
在一行中输出给定字符在给定字符串中出现的次数。

输入样例:
programming is More fun!
m
输出样例:
2

#include 

using namespace std;

string s;
int cnt[300];

int main()
{
	getline(cin,s);
	for(int i=0;i<s.size();++i)
	{
		cnt[s[i]]++;
	}
	char c;c=getchar();
	cout<<cnt[c]<<endl;
	return 0;
}

7-4 IP地址转换

一个IP地址是用四个字节(每个字节8个位)的二进制码组成。请将32位二进制码表示的IP地址转换为十进制格式表示的IP地址输出。

输入格式:
输入在一行中给出32位二进制字符串。

输出格式:
在一行中输出十进制格式的IP地址,其由4个十进制数组成(分别对应4个8位的二进制数),中间用“.”分隔开。

输入样例:
11001100100101000001010101110010
输出样例:
204.148.21.114

#include 

using namespace std;


int main()
{
	char c;
	for(int i=0;i<4;++i)
	{
		int n=0;
		for(int j=0;j<8;++j)
		{
			c=getchar();
			n*=2;
			n+=c-'0';
		}
		if(i!=3)cout<<n<<".";
		else cout<<n;
	}
	return 0;
}

7-5 英文单词排序

本题要求编写程序,输入若干英文单词,对这些单词按长度从小到大排序后输出。如果长度相同,按照输入的顺序不变。

输入格式:
输入为若干英文单词,每行一个,以#作为输入结束标志。其中英文单词总数不超过20个,英文单词为长度小于10的仅由小写英文字母组成的字符串。

输出格式:
输出为排序后的结果,每个单词后面都额外输出一个空格。

输入样例:
blue
red
yellow
green
purple

输出样例:
red blue green yellow purple

#include 

using namespace std;

class node 
{
	public:
	string s;
	int len,id;
	node(string str,int a,int b){
		s=str;len=a;id=b;
	}
	node(){
	}
}ns[100];
int p;
bool cmp(node a,node b)
{
	if(a.len!=b.len)return a.len<b.len;
	return a.id<b.id;
}

int main()
{
	string s;
	while(cin>>s)
	{
		if(s=="#")break;
		ns[p++]=node(s,s.size(),p);
	}
	sort(ns,ns+p,cmp);
	for(int i=0;i<p;++i)cout<<ns[i].s<<" ";
	return 0;
}

7-6 藏尾诗

本题要求编写一个解密藏尾诗的程序。

输入格式:
输入为一首中文藏尾诗,一共四句。每句一行,但句子不一定是等长的,最短一个汉字,最长九个汉字。注意:一个汉字占两个字节。

输出格式:
取出每句的最后一个汉字并连接在一起形成一个字符串并输出。同时在末尾输入一个换行符。

输入样例:
悠悠田园风
然而心难平
兰花轻涌浪
兰香愈幽静
输出样例:
风平浪静

#include 

using namespace std;

string s[4],ans;

int main()
{
	for(int i=0;i<4;++i)cin>>s[i];
	for(int i=0;i<4;++i)
	{
		int len=s[i].size();
		ans+=s[i][len-2];
		ans+=s[i][len-1];
	}
	cout<<ans;
	return 0;
}

7-7 删除字符串中的子串

输入2个字符串S1和S2,要求删除字符串S1中出现的所有子串S2,即结果字符串中不能包含S2。

输入格式:
输入在2行中分别给出不超过80个字符长度的、以回车结束的2个非空字符串,对应S1和S2。

输出格式:
在一行中输出删除字符串S1中出现的所有子串S2后的结果字符串。

输入样例:
Tomcat is a male ccatat
cat
输出样例:
Tom is a male

java 的replace 直接替换,替换成空串,就等于删除子串

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc= new Scanner(System.in);
        String s1=sc.nextLine();
        String s2=sc.nextLine();
        String s3=s1.replace(s2,"");
        while(!s1.equals(s3)){
            s1=s3;
            s3=s1.replace(s2,"");
        }
        System.out.println(s3);
    }
}

cpp

直接手动模拟会很折磨
用string的find,结合erase或者replace会很舒适
#include 

using namespace std;

string s1,s2;

int main()
{
	getline(cin,s1);
	getline(cin,s2);
	
	while(s1.find(s2)!=s1.npos)
	{
		s1=s1.erase(s1.find(s2),s2.size());
	}
	cout<<s1;
	return 0;
}
#include 

using namespace std;

string s1,s2;

int main()
{
	getline(cin,s1);
	getline(cin,s2);
	
	while(s1.find(s2)!=s1.npos)
	{
		s1=s1.replace(s1.find(s2),s2.size(),"",0,0);
	}
	cout<<s1;
	return 0;
}

7-8 字符串的冒泡排序

我们已经知道了将N个整数按从小到大排序的冒泡排序法。本题要求将此方法用于字符串序列,并对任意给定的K(

输入格式:
输入在第1行中给出N和K(1≤K

输出格式:
输出冒泡排序法扫描完第K遍后的中间结果序列,每行包含一个字符串。

输入样例:
6 2
best
cat
east
a
free
day
输出样例:
best
a
cat
day
east
free

#include 

using namespace std;

string s[1000];

int main()
{
	int n,k;cin>>n>>k;
	for(int i=0;i<n;++i)cin>>s[i];
	
	for(int i=n-1;i>n-1-k;--i)
	{
		for(int j=0;j<i;++j)
		{
			if(s[j]>s[j+1])swap(s[j],s[j+1]);
		}
	}
	for(int i=0;i<n;++i)cout<<s[i]<<endl;
	return 0;
}

7-9 字符串循环左移

输入一个字符串和一个非负整数N,要求将字符串循环左移N次。

输入格式:
输入在第1行中给出一个不超过100个字符长度的、以回车结束的非空字符串;第2行给出非负整数N。

输出格式:
在一行中输出循环左移N次后的字符串。

输入样例:
Hello World!
2
输出样例:
llo World!He

#include 

using namespace std;

string s,t;
int k;

int main()
{
	getline(cin,s);cin>>k;
	k%=s.size();
	t=s.substr(0,k);
	s=s.erase(0,k);
	s+=t;
	cout<<s;
	return 0;
}

7-10 说反话-加强版

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

输入格式:
测试输入包含一个测试用例,在一行内给出总长度不超过500 000的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用若干个空格分开。

输出格式:
每个测试用例的输出占一行,输出倒序后的句子,并且保证单词间只有1个空格。

输入样例:
Hello World Here I Come

#include 

using namespace std;

string s;
stack<string> stk;

int main()
{
	while(cin>>s)stk.push(s);
	while(!stk.empty())
	{
        if(stk.size()!=1)
		cout<<stk.top()<<" ";
        else cout<<stk.top();
		stk.pop();
	}
	return 0;
}

7-11 切分表达式——写个tokenizer吧

[先说点出题背景]

这个题是为低年级同学、学C语言的同学准备的,因为,对这部分同学,这个题目编写起来略有一点复杂。如果是高年级、学过了正则表达式(Regular Expression)的同学或者学过了Java等OO语言的同学做这个题,应当发现这题比较简单吧。哦,对了,什么是tokenizer?请自行查询解决。反正在此处不应翻译成“令牌解析器”。

[正题]

四则运算表达式由运算数(必定包含数字,可能包含正或负符号、小数点)、运算符(包括+、-、*、/)以及小括号((和))组成,每个运算数、运算符和括号都是一个token(标记)。现在,对于给定的一个四则运算表达式,请把她的每个token切分出来。题目保证给定的表达式是正确的,不需要做有效性检查。

输入格式:
在一行中给出长度不超过40个字符的表达式,其中没有空格,仅由上文中token的字符组成

输出格式:
依次输出表达式中的tokens,每个token占一行。
输入样例:
32*((2-2)+5)/(-15)
输出样例:
32
*
(
(
2

2
)
+
5
)
/
(
-15
)

纯模拟,不知道有没有更好的解法

一开始的思路是用个标记,标记上一个已经输出的类型是什么,一次来判断正负号是运算符还是符号,但是这样不知道有什么问题,反正样例是过去了,而如下的写法还更加简便,也通过了
#include 

using namespace std;
queue<string> q;
int main()
{
	string s,t="";cin>>s;
	for(int i=0;i<s.size();++i)
	{
		if(s[i]=='('||s[i]==')'||s[i]=='*'||s[i]=='/'){
			string m="";m+=s[i];
			q.push(m);continue;
		}
		if(s[i]=='-'||s[i]=='+'){
			if(s[i-1]==')'||isdigit(s[i-1]))
			{
				string m="";m+=s[i];
				q.push(m);continue;
			}
		}
		t+=s[i];
		if(isdigit(s[i])&&!isdigit(s[i+1])&&s[i+1]!='.'){
			q.push(t);t="";
		}
	}
	while(!q.empty())
	{
		if(q.size()!=1)cout<<q.front()<<endl;
		else cout<<q.front();
		q.pop();
	}
	return 0;
}

7-12 输出GPLT

给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序,按GPLTGPLT…这样的顺序输出,并忽略其它字符。当然,四种字符(不区分大小写)的个数不一定是一样多的,若某种字符已经输出完,则余下的字符仍按GPLT的顺序打印,直到所有字符都被输出。

输入格式:
输入在一行中给出一个长度不超过10000的、仅由英文字母构成的非空字符串。

输出格式:
在一行中按题目要求输出排序后的字符串。题目保证输出非空。

输入样例:
pcTclnGloRgLrtLhgljkLhGFauPewSKgt
输出样例:
GPLTGPLTGLTGLGLL

#include 

using namespace std;

int cnt[300],n;

int main()
{
	string s;cin>>s;
	for(int i=0;i<s.size();++i)
	{
		s[i]=toupper(s[i]);
		cnt[s[i]]++;
		if(s[i]=='G'||s[i]=='P'||s[i]=='L'||s[i]=='T')n++;
	}
	while(n)
	{
		if(cnt['G'])
		{
			cout<<"G";cnt['G']--;n--;
		}
		if(cnt['P'])
		{
			cout<<"P";cnt['P']--;n--;
		}
		if(cnt['L'])
		{
			cout<<"L";cnt['L']--;n--;
		}
		if(cnt['T'])
		{
			cout<<"T";cnt['T']--;n--;
		}
	}
	return 0;
}

7-13 Left-pad

根据新浪微博上的消息,有一位开发者不满NPM(Node Package Manager)的做法,收回了自己的开源代码,其中包括一个叫left-pad的模块,就是这个模块把javascript里面的React/Babel干瘫痪了。这是个什么样的模块?就是在字符串前填充一些东西到一定的长度。例如用去填充字符串GPLT,使之长度为10,调用left-pad的结果就应该是*****GPLT。Node社区曾经对left-pad紧急发布了一个替代,被严重吐槽。下面就请你来实现一下这个模块。

输入格式:
输入在第一行给出一个正整数N(≤10
4
)和一个字符,分别是填充结果字符串的长度和用于填充的字符,中间以1个空格分开。第二行给出原始的非空字符串,以回车结束。

输出格式:
在一行中输出结果字符串。

输入样例1:
15 _
I love GPLT
输出样例1:
____I love GPLT
输入样例2:
4 *
this is a sample for cut
输出样例2:
cut

#include 

using namespace std;

int main()
{
	int n;char c;cin>>n>>c;getchar();
	string s;getline(cin,s);
	if(s.size()>=n)s=s.substr(s.size()-n,n);
	else s=s.insert(0,(n-s.size()),c);
	cout<<s;
	return 0;
}

7-14 A-B

本题要求你计算A−B。不过麻烦的是,A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A−B。

输入格式:
输入在2行中先后给出字符串A和B。两字符串的长度都不超过10
4
,并且保证每个字符串都是由可见的ASCII码和空白字符组成,最后以换行符结束。

输出格式:
在一行中打印出A−B的结果字符串。

输入样例:
I love GPLT! It’s a fun game!
aeiou
输出样例:
I lv GPLT! It’s fn gm!

#include 

using namespace std;

string a,b;
int main()
{
	getline(cin,a);
	getline(cin,b);
	for(int i=0;i<b.size();++i)
	{
		int t=a.find(b[i]);
		while(t!=a.npos)
		{
			a.erase(t,1);
			t=a.find(b[i]);
		}
	}
	cout<<a; 
	return 0;
}
#include 

using namespace std;

string a,b;
int m[300];
int main()
{
	getline(cin,a);
	getline(cin,b);
	for(int i=0;i<b.size();++i)m[b[i]]=1;
	for(int i=0;i<a.size();++i)if(!m[a[i]])cout<<a[i];
	return 0;
}

7-15 最长对称子串

对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11。

输入格式:
输入在一行中给出长度不超过1000的非空字符串。

输出格式:
在一行中输出最长对称子串的长度。

输入样例:
Is PAT&TAP symmetric?
输出样例:
11

#include 

using namespace std;

int f[1005][1005];
int ans;

int main()
{
	string s;getline(cin,s);if(s.size())ans=1;
	for(int i=0;i<s.size();++i)f[i][i]=1;
	
	for(int L=2;L<=s.size();++L)
	{
		for(int i=0;i+L-1<s.size();++i)
		{
			int j=i+L-1;
			if(s[i]==s[j])
			{
				if(L<=3)f[i][j]=1;
				else
				{
					f[i][j]=f[i+1][j-1];
				}
				if(f[i][j])ans=L;
			}
		}
	}
	cout<<ans;
	return 0;
}

7-16 古风排版

中国的古人写文字,是从右向左竖向排版的。本题就请你编写程序,把一段文字按古风排版。

输入格式:
输入在第一行给出一个正整数N(<100),是每一列的字符数。第二行给出一个长度不超过1000的非空字符串,以回车结束。

输出格式:
按古风格式排版给定的字符串,每列N个字符(除了最后一列可能不足N个)。

输入样例:
4
This is a test case
输出样例:
asa T
st ih
e tsi
ce s

输出只能用两重循环,需要手动计算当前二维坐标映射到字符串中的一维坐标,同时要注意除法取整问题
#include 

using namespace std;

int main()
{
	int n,m;string s;cin>>n;getchar();getline(cin,s);
	if(s.size()%n!=0)m=(s.size()+n)/n;
	else m=s.size()/n;
	for(int i=0;i<n;++i)
	{
		for(int j=0;j<m;++j)
		{
			int t=m-1-j;
			t*=n;
			t+=i;
			if(t<s.size())cout<<s[t];
			else cout<<" "; 
		}
		if(i!=n-1)
		cout<<endl;
	}
	return 0;
}

7-17 猜数字

一群人坐在一起,每人猜一个 100 以内的数,谁的数字最接近大家平均数的一半就赢。本题就要求你找出其中的赢家。

输入格式:
输入在第一行给出一个正整数N(≤10
4
)。随后 N 行,每行给出一个玩家的名字(由不超过8个英文字母组成的字符串)和其猜的正整数(≤ 100)。

输出格式:
在一行中顺序输出:大家平均数的一半(只输出整数部分)、赢家的名字,其间以空格分隔。题目保证赢家是唯一的。

输入样例:
7
Bob 35
Amy 28
James 98
Alice 11
Jack 45
Smith 33
Chris 62
输出样例:
22 Amy

#include 

using namespace std;

class node
{
	public:
		string s;
		double x;
}ns[10005];
double num;

bool cmp(node a,node b)
{
	return a.x<b.x;
}
int main()
{
	int n;cin>>n;
	for(int i=0;i<n;++i)
	{
		cin>>ns[i].s>>ns[i].x;
		num+=ns[i].x;
	}
	num/=n;num/=2;
	cout<<floor(num)<<" ";
	sort(ns,ns+n,cmp);
	bool flag=true;
	for(int i=0;i<n-1;++i)
	{
		if(fabs(ns[i].x-num)<fabs(ns[i+1].x-num))
		{
			flag=false;
			cout<<ns[i].s;break;
		}
	}
	if(flag)cout<<ns[n-1].s;
	return 0;
}

7-18 估值一亿的AI核心代码

AI.jpg

以上图片来自新浪微博。

本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是:

无论用户说什么,首先把对方说的话在一行中原样打印出来;
消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
把原文中所有大写英文字母变成小写,除了 I;
把原文中所有独立的 can you、could you 对应地换成 I can、I could—— 这里“独立”是指被空格或标点符号分隔开的单词;
把原文中所有独立的 I 和 me 换成 you;
把原文中所有的问号 ? 换成惊叹号 !;
在一行中输出替换后的句子作为 AI 的回答。
输入格式:
输入首先在第一行给出不超过 10 的正整数 N,随后 N 行,每行给出一句不超过 1000 个字符的、以回车结尾的用户的对话,对话为非空字符串,仅包括字母、数字、空格、可见的半角标点符号。

输出格式:
按题面要求输出,每个 AI 的回答前要加上 AI: 和一个空格。

输入样例:
6
Hello ?
Good to chat with you
can you speak Chinese?
Really?
Could you show me 5
What Is this prime? I,don 't know
输出样例:
Hello ?
AI: hello!
Good to chat with you
AI: good to chat with you
can you speak Chinese?
AI: I can speak chinese!
Really?
AI: really!
Could you show me 5
AI: I could show you 5
What Is this prime? I,don 't know
AI: what Is this prime! you,don’t know

太复杂了,懒得去调
借鉴别人的代码


#include
#include
#include
#include
#include
using namespace std;
int d(char x)
{
	if (x >= 'A'&&x <= 'Z') return -1;
	if (x >= 'a'&&x <= 'z') return -2;
	if (x >= '0'&&x <= '9') return -3;
	if (x == ' ') return 2;
	return 1;
}
string low(string str)
{
	string b;
	b += " ";
	for (int i = 0; i < str.size(); i++)
	{
		if (str[i] >= 'A'&&str[i] <= 'Z'&&str[i] != 'I')
		{
			str[i] += 32;
		}
		if (str[i] == '?') str[i] = '!';
	}
	b += str;
	b += " ";
	str.clear();
	str += " ";
	for (int i = 1; i < b.size() - 1; i++)
	{
		if (b[i] == ' ' && b[i - 1] == ' ')	continue;
		else if (d(b[i + 1]) == 1 && b[i] == ' ')	continue;
		else	str += b[i];
	}
	str += " ";
	return str;
}
int main()
{
	int t, i, j, k;
	string str;
	cin >> t;
	getchar();
	while (t--)
	{
		getline(cin, str);
		cout << str << endl;
		cout << "AI: ";
		bool kong = false;
		for (i = 0; i < str.size(); i++)
		{
			if (str[i] != ' ')
			{
				kong = true;
				break;
			}
		}
		if (kong == false)
		{
			cout << endl;
			continue;
		}
		str = low(str);
		string temp;
		for (i = 0; i < str.size(); i++)
		{
			temp += str[i];
			if (d(str[i])>0 && str[i + 1] == 'm'&&str[i + 2] == 'e'&&d(str[i + 3])>0)
			{
				i += 2;
				temp += "you";
			}
			else if (d(str[i])>0 && str[i + 1] == 'I'&&d(str[i + 2])>0)
			{
				i++;
				temp += "you";
			}
			else if (d(str[i])>0 && str[i + 1] == 'c'&& str[i + 2] == 'a'&& str[i + 3] == 'n'&& str[i + 5] == 'y'&& str[i + 6] == 'o'&& str[i + 7] == 'u'&&d(str[i + 8])>0)
			{
				i += 7;
				temp += "I can";
			}
			else if (d(str[i])>0 && str[i + 1] == 'c'&& str[i + 2] == 'o'&& str[i + 3] == 'u'&& str[i + 4] == 'l'&& str[i + 5] == 'd'&&  str[i + 7] == 'y'&& str[i + 8] == 'o'&& str[i + 9] == 'u'&&d(str[i + 10])>0)
			{
				i += 9;
				temp += "I could";
			}
		}
		str = "";
		str += temp;
		//cout << str << endl;
		int len;
		for (i = str.size() - 1; i >= 0; i--)
		{
			if (str[i] != ' ')
			{
				len = i;
				break;
			}
		}
		int cnt = 0;
		for (i = 0; i <= len; i++)
		{
			if (i>0 && str[i] == ' '&& d(str[i + 1]) == 1)	continue;
			if (str[i] != ' ')  cout << str[i], cnt++;
			else if (cnt>0) cout << " ";
		}
		cout << endl;
	}
	return 0;
}

7-19 口罩发放

为了抗击来势汹汹的 COVID19 新型冠状病毒,全国各地均启动了各项措施控制疫情发展,其中一个重要的环节是口罩的发放。

某市出于给市民发放口罩的需要,推出了一款小程序让市民填写信息,方便工作的开展。小程序收集了各种信息,包括市民的姓名、身份证、身体情况、提交时间等,但因为数据量太大,需要根据一定规则进行筛选和处理,请你编写程序,按照给定规则输出口罩的寄送名单。

输入格式:
输入第一行是两个正整数 D 和 P(1≤D,P≤30),表示有 D 天的数据,市民两次获得口罩的时间至少需要间隔 P 天。

接下来 D 块数据,每块给出一天的申请信息。第 i 块数据(i=1,⋯,D)的第一行是两个整数 T
i

和 S
i

(1≤T
i

,S
i

≤1000),表示在第 i 天有 T
i

条申请,总共有 S
i

个口罩发放名额。随后 T
i

行,每行给出一条申请信息,格式如下:

姓名 身份证号 身体情况 提交时间
给定数据约束如下:

姓名 是一个长度不超过 10 的不包含空格的非空字符串;
身份证号 是一个长度不超过 20 的非空字符串;
身体情况 是 0 或者 1,0 表示自觉良好,1 表示有相关症状;
提交时间 是 hh:mm,为24小时时间(由 00:00 到 23:59。例如 09:08。)。注意,给定的记录的提交时间不一定有序;
身份证号 各不相同,同一个身份证号被认为是同一个人,数据保证同一个身份证号姓名是相同的。
能发放口罩的记录要求如下:

身份证号 必须是 18 位的数字(可以包含前导0);
同一个身份证号若在第 i 天申请成功,则接下来的 P 天不能再次申请。也就是说,若第 i 天申请成功,则等到第 i+P+1 天才能再次申请;
在上面两条都符合的情况下,按照提交时间的先后顺序发放,直至全部记录处理完毕或 S
i

个名额用完。如果提交时间相同,则按照在列表中出现的先后顺序决定。
输出格式:
对于每一天的申请记录,每行输出一位得到口罩的人的姓名及身份证号,用一个空格隔开。顺序按照发放顺序确定。

在输出完发放记录后,你还需要输出有合法记录的、身体状况为 1 的申请人的姓名及身份证号,用空格隔开。顺序按照申请记录中出现的顺序确定,同一个人只需要输出一次。

输入样例:
4 2
5 3
A 123456789012345670 1 13:58
B 123456789012345671 0 13:58
C 12345678901234567 0 13:22
D 123456789012345672 0 03:24
C 123456789012345673 0 13:59
4 3
A 123456789012345670 1 13:58
E 123456789012345674 0 13:59
C 123456789012345673 0 13:59
F F 0 14:00
1 3
E 123456789012345674 1 13:58
1 1
A 123456789012345670 0 14:11
输出样例:
D 123456789012345672
A 123456789012345670
B 123456789012345671
E 123456789012345674
C 123456789012345673
A 123456789012345670
A 123456789012345670
E 123456789012345674
样例解释:
输出中,第一行到第三行是第一天的部分;第四、五行是第二天的部分;第三天没有符合要求的市民;第六行是第四天的部分。最后两行按照出现顺序输出了可能存在身体不适的人员。

写了好久不知道错哪了,有个测试点过不去,23分
23分代码

#include 

using namespace std;

int d,pp;
class node
{
	public :
	string xm,sf,zk,time;int sx;
	node(string xm,string sf,string zk,string time,int sx)
	{
		this->xm=xm;
		this->sf=sf;
		this->zk=zk;
		this->time=time;
		this->sx=sx;
	}
	node(){
	}
}ns[30005];
node tmp[10005];
map<string,int> mp,mp2;
int cnt;

bool cmp(node a,node b)
{
	if(a.time!=b.time)
	{
		return a.time<b.time;
	}
	return a.sx<b.sx;
}

int main()
{
	cin>>d>>pp;
	for(int i=1;i<=d;++i)
	{
		int t,s;cin>>t>>s;
		int p=0;
		for(int j=1;j<=t;++j)
		{
			string xm,sf,zk,time;cin>>xm>>sf>>zk>>time;
			
			bool flag=true;
			if(sf.size()!=18)flag=false;
			for(int k=0;k<sf.size();++k)if(!isdigit(sf[k]))flag=false;
			if(flag==false)continue;
			
			ns[cnt++]=node(xm,sf,zk,time,cnt);
			
			
			if(mp[sf]!=0&&i-mp[sf]<=pp)continue;
			tmp[p++]=node(xm,sf,zk,time,cnt);
			//mp[sf]=i;
		}
		sort(tmp,tmp+p,cmp);
		for(int j=0;j<min(s,p);++j)
		{
			cout<<tmp[j].xm<<" "<<tmp[j].sf<<endl;
			mp[tmp[j].sf]=i;
		}
	}
	
	for(int i=0;i<cnt;++i)
	{
		if(ns[i].zk=="1")
		{
			if(mp2[ns[i].sf]==0)
			{
				cout<<ns[i].xm<<" "<<ns[i].sf<<endl;
				mp2[ns[i].sf]=1;
			}
		}
	}

	return 0;
}

AC代码

#include 
using namespace std;
struct node {
	string name, id, Time;
	int illness, order;
};
bool isIllegal(const string &ss) {
	if (ss.size() != 18) return true;
	for (char i:ss) if (i < '0' || i > '9') return true;
	return false;
}
bool cmp (const node &a,const node &b) {
	if (a.Time != b.Time) return a.Time < b.Time;
	return a.order < b.order;
}
vector<node> Record, ill;
int D, P, t, s, providedNum;
map<string, int> lastGet;
set<string> gotten;
int main() {
	cin >> D >> P;
	for (int i = 1; i <= D; i++) {
		cin >> t >> s;
		Record.resize(t);
		providedNum = 0;
		for (int j = 0; j < t; j++) {
			cin >> Record[j].name >> Record[j].id >> Record[j].illness >> Record[j].Time;
			Record[j].order = j;
			if (isIllegal(Record[j].id)) Record[j].name = "";
			else {
				if (!lastGet.count(Record[j].id)) lastGet[Record[j].id] = -30;
				if (Record[j].illness == 1 && !gotten.count(Record[j].id)) {
					ill.push_back(Record[j]);
					gotten.insert(Record[j].id);
				}
			}
		}
		sort(Record.begin(), Record.end(), cmp);
		for (int j = 0; j < t && providedNum < s; j++) {
			if (Record[j].name != "" && i - lastGet[Record[j].id] > P) {
				lastGet[Record[j].id] = i;
				providedNum++;
				cout << Record[j].name << ' ' << Record[j].id << endl;
			}
		}
	}
	for (node i:ill) cout << i.name << ' ' << i.id << '\n';
	return 0;
}

7-20 凯撒密码

为了防止信息被别人轻易窃取,需要把电码明文通过加密方式变换成为密文。输入一个以回车符为结束标志的字符串(少于80个字符),再输入一个整数offset,用凯撒密码将其加密后输出。恺撒密码是一种简单的替换加密技术,将明文中的所有字母都在字母表上偏移offset位后被替换成密文,当offset大于零时,表示向后偏移;当offset小于零时,表示向前偏移。

输入格式:
输入第一行给出一个以回车结束的非空字符串(少于80个字符);第二行输入一个整数offset。

输出格式:
输出加密后的结果字符串。

输入样例1:
Hello Hangzhou
2
输出样例1:
Jgnnq Jcpibjqw
输入样例2:
a=x+y
-1
输出样例2:
z=w+x

坑点提示:char型变量范围-128到127,而’z’=122,计算偏移过程中可能会发生溢出,需要使用int型作为中间变量来过渡
#include 

using namespace std;

int main()
{
	string s;getline(cin,s);int p;cin>>p; 
	for(int i=0;i<s.size();++i)
	{
		if(isalpha(s[i]))
		{
			int t=p%26;
			if(s[i]>='a')
			{
				int c=s[i];
				c+=t;
				if(c>'z')c-=26;
				else if(c<'a')c+=26;
				s[i]=c;
			}
			else
			{
				int c=s[i];
				c+=t;
				if(c>'Z')c-=26;
				else if(c<'A')c+=26;
				s[i]=c;
			}
		}
	}
	cout<<s;
	return 0;
}

7-21 吉老师的回归

曾经在天梯赛大杀四方的吉老师决定回归天梯赛赛场啦!

为了简化题目,我们不妨假设天梯赛的每道题目可以用一个不超过 500 的、只包括可打印符号的字符串描述出来,如:Problem A: Print “Hello world!”。

众所周知,吉老师的竞赛水平非常高超,你可以认为他每道题目都会做(事实上也是……)。因此,吉老师会按照顺序看题并做题。但吉老师水平太高了,所以签到题他就懒得做了(浪费时间),具体来说,假如题目的字符串里有 qiandao 或者 easy(区分大小写)的话,吉老师看完题目就会跳过这道题目不做。

现在给定这次天梯赛总共有几道题目以及吉老师已经做完了几道题目,请你告诉大家吉老师现在正在做哪个题,或者吉老师已经把所有他打算做的题目做完了。

提醒:天梯赛有分数升级的规则,如果不做签到题可能导致团队总分不足以升级,一般的选手请千万不要学习吉老师的酷炫行为!

输入格式:
输入第一行是两个正整数 N,M (1≤M≤N≤30),表示本次天梯赛有 N 道题目,吉老师现在做完了 M 道。

接下来 N 行,每行是一个符合题目描述的字符串,表示天梯赛的题目内容。吉老师会按照给出的顺序看题——第一行就是吉老师看的第一道题,第二行就是第二道,以此类推。

输出格式:
在一行中输出吉老师当前正在做的题目对应的题面(即做完了 M 道题目后,吉老师正在做哪个题)。如果吉老师已经把所有他打算做的题目做完了,输出一行 Wo AK le。

输入样例 1:
5 1
L1-1 is a qiandao problem.
L1-2 is so…easy.
L1-3 is Easy.
L1-4 is qianDao.
Wow, such L1-5, so easy.
输出样例 1:
L1-4 is qianDao.
输入样例 2:
5 4
L1-1 is a-qiandao problem.
L1-2 is so easy.
L1-3 is Easy.
L1-4 is qianDao.
Wow, such L1-5, so!!easy.
输出样例 2:
Wo AK le

#include 

using namespace std;

int main()
{
	int n,m;cin>>n>>m;getchar();
	string s,ans;
	bool flag=true;
	while(n--)
	{
		getline(cin,s);
		if(s.find("qiandao")!=s.npos||s.find("easy")!=s.npos)continue;
		if(m==0)flag=false,ans=s;
		m--;
	}
	if(flag)ans="Wo AK le";
	cout<<ans; 
	return 0;
}

你可能感兴趣的:(天梯赛,c++,字符串)