实验四
一. 7-1 简单求阶乘问题
本题要求编写程序,计算N的阶乘。
输入格式:
输入在一行中给出一个不超过12的正整数N。
输出格式:
在一行中输出阶乘的值。
输入样例:
4
输出样例:
24
参考答案:
#include<iostream>
using namespace std;
int f(int n){
if(n==1||n==0){
return 1;
}
return n*f(n-1);
}
int main(){
int n;
cin>>n;
cout<<f(n);
return 0;
}
二. 7-2 出生年
以上是新浪微博中一奇葩贴:“我出生于1988年,直到25岁才遇到4个数字都不相同的年份。”也就是说,直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的年份”这句话。
输入格式:
输入在一行中给出出生年份y和目标年份中不同数字的个数n,其中y在[1, 3000]之间,n可以是2、或3、或4。注意不足4位的年份要在前面补零,例如公元1年被认为是0001年,有2个不同的数字0和1。
输出格式:
根据输入,输出x和能达到要求的年份。数字间以1个空格分隔,行首尾不得有多余空格。年份要按4位输出。注意:所谓“n个数字都不相同”是指不同的数字正好是n个。如“2013”被视为满足“4位数字都不同”的条件,但不被视为满足2位或3位数字不同的条件。
输入样例1:
1988 4
输出样例1:
25 2013
输入样例2:
1 2
输出样例2:
0 0001
参考答案:
#include<iostream>
#include<set>
using namespace std;
bool isValid(int Y,int num){
string s = to_string(Y);
set<char>mySet;
if(s.size()<4){
for(char c:s){
mySet.insert(c);
}
mySet.insert('0');
return mySet.size()==num;
}
for(char c:s){
mySet.insert(c);
}
return mySet.size()==num;
}
string toString(int num){
string s = "0000";
string origin = to_string(num);
int i = origin.size()-1;
int j = s.size()-1;
while(i>=0){
s[j--] = origin[i--];
}
return s;
}
int main(){
int Y,num;
cin>>Y>>num;
int index = 0;
while(true){
if(isValid(Y+index,num)){
cout<<index<<" "<<toString(Y+index);
return 0;
}
index++;
}
return 0;
}
三. 7-3 验证“哥德巴赫猜想”
数学领域著名的“哥德巴赫猜想”的大致意思是:任何一个大于2的偶数总能表示为两个素数之和。比如:24=5+19,其中5和19都是素数。本实验的任务是设计一个程序,验证20亿以内的偶数都可以分解成两个素数之和。
输入格式:
输入在一行中给出一个(2, 2 000 000 000]范围内的偶数N。
输出格式:
在一行中按照格式“N = p + q”输出N的素数分解,其中p ≤ q均为素数。又因为这样的分解不唯一(例如24还可以分解为7+17),要求必须输出所有解中p最小的解。
输入样例:
24
输出样例:
24 = 5 + 19
参考答案:
#include<iostream>
#include<cmath>
using namespace std;
bool isValid(long long n){
if(n<2)return false;
for(long long i=2;i*i<=n;i++){
if(n%i==0)return false;
}
return true;
}
int main(){
long long n;
cin>>n;
for(long long i=2;i<=n/2;i++){
if(isValid(i)&&isValid(n-i)){
cout<<n<<" = "<<i<<" + "<<n-i;
return 0;
}
}
return 0;
}
四. 7-4 谷歌的招聘
2004 年 7 月,谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌(如下图)用于招聘。内容超级简单,就是一个以 .com 结尾的网址,而前面的网址是一个 10 位素数,这个素数是自然常数 e 中最早出现的 10 位连续数字。能找出这个素数的人,就可以通过访问谷歌的这个网站进入招聘流程的下一步。

自然常数 e 是一个著名的超越数,前面若干位写出来是这样的:e = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921... 其中粗体标出的 10 位数就是答案。
本题要求你编程解决一个更通用的问题:从任一给定的长度为 L 的数字中,找出最早出现的 K 位连续数字所组成的素数。
输入格式:
输入在第一行给出 2 个正整数,分别是 L(不超过 1000 的正整数,为数字长度)和 K(小于 10 的正整数)。接下来一行给出一个长度为 L 的正整数 N。
输出格式:
在一行中输出 N 中最早出现的 K 位连续数字所组成的素数。如果这样的素数不存在,则输出 404。注意,原始数字中的前导零也计算在位数之内。例如在 200236 中找 4 位素数,0023 算是解;但第一位 2 不能被当成 0002 输出,因为在原始数字中不存在这个 2 的前导零。
输入样例 1:
20 5
23654987725541023819
输出样例 1:
49877
输入样例 2:
10 3
2468001680
输出样例 2:
404
参考答案:
#include<iostream>
using namespace std;
bool isValid(long long n){
if(n<2)return false;
for(long long i=2;i*i<=n;i++){
if(n%i==0)return false;
}
return true;
}
int main(){
int L,N;
cin>>L>>N;
if(L<N){
cout<<"404";
return 0;
}
string s;
cin>>s;
int pos = 0;
while(pos<=s.size()-N){
string sub = s.substr(pos++,N);
if(isValid(stol(sub))){
cout<<sub;
return 0;
}
}
cout<<"404";
return 0;
}
五. 7-5 估值一亿的AI核心代码

以上图片来自新浪微博。
本题要求你实现一个稍微更值钱一点的 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<iostream>
using namespace std;
string process(string s){
while(s[0]==' ') s.erase(s.begin());//去掉句首的空格
while(s.back()==' ') s.erase(s.end()-1);//去掉句尾的空格
for(int i=0;i<s.size();i++)
{
if(s[i]==' ')
{
while(s[i+1]==' ') s.erase(s.begin()+i+1);//句中多个空格,只保留一个
if(!isalnum(s[i+1])) s.erase(s.begin()+i);//去掉符号前面的空格
}
}
for(auto &x:s)
{
if(x>='A'&&x<='Z'&&x!='I') x=x-'A'+'a';//大写转化为小写
}
for(int i=0;;i++)
{
i=s.find("can you",i);//查找"can you"出现的位置
if(i==-1) break;//没有找到
//位置为0或者当前位置前不能为字母或者数字,并且后面一个字符也不能是字母或者数字
if((i==0||!isalnum(s[i-1]))&&(i==s.size()-7||!isalnum(s[i+7])))
s.replace(i,7,"@ can");//将i后7个位置替换成"@ can"
}
for(int i=0;;i++)
{
i=s.find("could you",i);
if(i==-1) break;
if((i==0||!isalnum(s[i-1]))&&(i==s.size()-9||!isalnum(s[i+9])))
s.replace(i,9,"@ could");
}
for(int i=0;;i++)
{
i=s.find("I",i);
if(i==-1) break;
if((i==0||!isalnum(s[i-1]))&&(i==s.size()-1||!isalnum(s[i+1])))
s.replace(i,1,"you");
}
for(int i=0;;i++)
{
i=s.find("me",i);
if(i==-1) break;
if((i==0||!isalnum(s[i-1]))&&(i==s.size()-2||!isalnum(s[i+2])))
s.replace(i,2,"you");
}
for(auto &x:s)
{
if(x=='@') x='I';//因为I会换成you所以先换成@然后再换回来
if(x=='?') x='!';
}
return s;
}
int main(){
int n;
cin>>n;
getchar();
while(n-->0){
string s;
getline(cin,s);
cout<<s<<endl;
cout<<"AI: "<<process(s)<<endl;
}
return 0;
}