清华机试真题

题目感觉比较模式,中规中矩,但是很容易超时或者是有些复杂情况覆盖不到

进制转换

题目描述
将一个长度最多为30位数字的十进制非负整数转换为二进制数输出。
输入描述:
多组数据,每行为一个长度不超过30位的十进制非负整数。
(注意是10进制数字的个数可能有30个,而非30bits的整数)
输出描述:
每行输出对应的二进制数。
示例1 
输入
复制
0
1
3
8
输出
复制
0
1
11
1000

 数字长度过长,long long 类型也无法存储,使用字符串存储

#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;

string div2(string input){
//	cout<<"div:"<<input<<endl;
	int rmd=0;
	int shang=0;
	string res;
	for(int i=0;i<input.size();i++){
		shang=(rmd*10+input[i]-'0')/2;
		res.push_back(shang+'0');
		rmd=(rmd*10+input[i]-'0')%2;
	}
	while(res.size()>0){
		if(res[0]=='0')
			res.erase(res.begin());
		else
			break;
	}
//	cout<<"div2"<<endl;
	if(res.size()==0){
		return "0";
	}
	
	return res;
}

char rmd2(string input){
//	cout<<"rmd:"<<input<<endl;
	if((input[input.size()-1]-'0')%2==0){
		return '0';
	}
	else{
		return '1';
	}
}

string getres(string input){
//	cout<<"getres:"<<input<<endl;
	string res;
	char rmd;
	while(input!="0"){
		rmd=rmd2(input);
		input=div2(input);
		res.insert(res.begin(),rmd);
	}
	if(res.size()==0)
		return "0";
	return res;
}

int main(){
	string input;
	while(cin>>input){
		cout<<getres(input)<<endl;
	}
}

成绩排序

查找和排序 
题目:输入任意(用户,成绩)序列,可以获得成绩从高到低或从低到高的排列,相同成绩
都按先录入排列在前的规则处理。 
示例:
jack      70
peter     96
Tom       70
smith     67 
从高到低  成绩 
peter     96 
jack      70 
Tom       70 
smith     67 
从低到高 
smith     67 
jack      70 
Tom      70 
peter     96 
输入描述:
输入多行,先输入要排序的人的个数,然后输入排序方法0(降序)或者1(升序)再分别输入他们的名字和成绩,以一个空格隔开
输出描述:
按照指定方式输出名字和成绩,名字和成绩之间以一个空格隔开
示例1 
输入
复制
3
0
fang 90
yang 50
ning 70
输出
复制
fang 90
ning 70
yang 50

排序,结构体定义,重载操作符,注意审题

#include<vector>
#include<algorithm>
using namespace std;

struct record{
	string name;
	int score;
	int count;
	int asc;
	
	bool operator < (const record& r) const{
		if(score!=r.score)
			return score<r.score;
		else{
			if(asc==0)
				return count>r.count;
			else
				return count<r.count;
		}
	}
};


int main(){
	int n,asc;
	int count;
	
	while(cin>>n){
		count=0;
	cin>>asc;
	vector<record> re;
	while(n--){
		record temp;
		cin>>temp.name;
		cin>>temp.score;
		temp.count=count;
		temp.asc=asc;
		re.push_back(temp);
		count++;
	}
	sort(re.begin(),re.begin()+re.size());
	if(asc==1){
		for(int i=0;i<re.size();i++){
			cout<<re[i].name<<" "<<re[i].score<<endl;
		}
	}
	else if(asc==0){
		for(int i=re.size()-1;i>=0;i--){
			cout<<re[i].name<<" "<<re[i].score<<endl;
		}
	}
}
}

约数的个数

输入n个整数,依次输出每个数的约数的个数
输入描述:
输入的第一行为N,即数组的个数(N<=1000)
接下来的1行包括N个整数,其中每个数的范围为(1<=Num<=1000000000)
当N=0时输入结束。
输出描述:
可能有多组输入数据,对于每组输入数据,
输出N行,其中每一行对应上面的一个数的约数的个数。
示例1 
输入
复制
5
1 3 4 6 12
输出
复制
1
2
3
4
6

数的范围很大,直接暴力会超时,转化为开方

#include<iostream>
using namespace std;

int main(){
    int n;
    int tmp;
    while(cin>>n){
        while(n--){
            cin>>tmp;
            int sum=0;
            int i;
            for(i=1;i*i<tmp;i++){
            	if(tmp%i==0)
            		sum+=2;
			}
			if(i*i==tmp)
				sum++;
			cout<<sum<<endl;
        }
    }
}

代理服务器

题目描述
    使用代理服务器能够在一定程度上隐藏客户端信息,从而保护用户在互联网上的隐私。我们知道n个代理服务器的IP地址,现在要用它们去访问m个服务器。这 m 个服务器的 IP 地址和访问顺序也已经给出。系统在同一时刻只能使用一个代理服务器,并要求不能用代理服务器去访问和它 IP地址相同的服务器(不然客户端信息很有可能就会被泄露)。在这样的条件下,找到一种使用代理服务器的方案,使得代理服务器切换的次数尽可能得少。
输入描述:
    每个测试数据包括 n + m + 2 行。
    第 1 行只包含一个整数 n,表示代理服务器的个数。
    第 2行至第n + 1行每行是一个字符串,表示代理服务器的 IP地址。这n个 IP地址两两不相同。
    第 n + 2 行只包含一个整数 m,表示要访问的服务器的个数。
    第 n + 3 行至第 n + m + 2 行每行是一个字符串,表示要访问的服务器的 IP 地址,按照访问的顺序给出。
    每个字符串都是合法的IP地址,形式为“xxx.yyy.zzz.www”,其中任何一部分均是0–255之间的整数。输入数据的任何一行都不包含空格字符。
     其中,1<=n<=1000,1<=m<=5000。
输出描述:
    可能有多组测试数据,对于每组输入数据, 输出数据只有一行,包含一个整数s,表示按照要求访问服务器的过程中切换代理服务器的最少次数。第一次使用的代理服务器不计入切换次数中。若没有符合要求的安排方式,则输出-1。
示例1 
输入
复制
3
166.111.4.100
162.105.131.113
202.112.128.69
6
72.14.235.104
166.111.4.100
207.46.19.190
202.112.128.69
162.105.131.113
118.214.226.52
输出
复制
1

动态规划思想

#include<iostream>
#include<vector>
using namespace std;

int main(){
	int n;
	int MAX=6000;
	while(cin>>n){
		vector<string> agent(n);
		for(int i=0;i<n;i++){
			cin>>agent[i];
		} 
		int m;
		cin>>m;
		vector<string> server(m);
		for(int i=0;i<m;i++){
			cin>>server[i];
		}
		vector<vector<int> > dis(m+1);
		for(int i=0;i<m+1;i++){
			dis[i].resize(n);
			for(int j=0;j<n;j++){
				dis[i][j]=MAX;
			} 
		}
		for(int i=m-1;i>=0;i--){
			for(int j=0;j<n;j++){
				if(server[i]==agent[j]){
					dis[i][j]=0;
				}
				else{
					dis[i][j]=dis[i+1][j]+1;
				}
			}
		}
		int count=0;
		int index=0;
		int jndex=0;
		int max=0;
		for(int i=0;i<n;i++){
			if(max<dis[0][i]){
				index=i;
				max=dis[0][i];
			}
		}
		if(max==0){
			cout<<"-1"<<endl;
			break;
		}
		jndex=jndex+dis[0][index];
		while(jndex<m){
			max=0;
			index=0;
			for(int i=0;i<n;i++){
				if(max<dis[jndex][i]){
					index=i;
					max=dis[jndex][i];
				}
			}
			if(max==0){
				count=-1;
				break;
			}
			jndex=jndex+dis[jndex][index];
			count++;
		}
		cout<<count<<endl;
	} 
	
} 

手机键盘

题目描述
按照手机键盘输入字母的方式,计算所花费的时间 如:a,b,c都在“1”键上,输入a只需要按一次,输入c需要连续按三次。 如果连续两个字符不在同一个按键上,则可直接按,如:ad需要按两下,kz需要按6下 如果连续两字符在同一个按键上,则两个按键之间需要等一段时间,如ac,在按了a之后,需要等一会儿才能按c。 现在假设每按一次需要花费一个时间段,等待时间需要花费两个时间段。 现在给出一串字符,需要计算出它所需要花费的时间。
输入描述:
一个长度不大于100的字符串,其中只有手机按键上有的小写字母
输出描述:
输入可能包括多组数据,对于每组数据,输出按出Input所给字符串所需要的时间
示例1 
输入
复制
bob
www
输出
复制
7
7

能记起九宫格是什么样就行了

#include<iostream>
#include<vector>
using namespace std;

int main(){
	vector<int>pos(26);
	vector<int>time(26);
	pos[0]=2;
	time[0]=1;
	pos[1]=2;
	time[1]=2;
	pos[2]=2;
	time[2]=3;
	pos[3]=3;
	time[3]=1;
	pos[4]=3;
	time[4]=2;
	pos[5]=3;
	time[5]=3;
	pos[6]=4;
	time[6]=1;
	pos[7]=4;
	time[7]=2;
	pos[8]=4;
	time[8]=3;
	pos[9]=5;
	time[9]=1;
	pos[10]=5;
	time[10]=2;
	pos[11]=5;
	time[11]=3;
	pos[12]=6;
	time[12]=1;
	pos[13]=6;
	time[13]=2;
	pos[14]=6;
	time[14]=3;
	pos[15]=7;
	time[15]=1;
	pos[16]=7;
	time[16]=2;
	pos[17]=7;
	time[17]=3;
	pos[18]=7;
	time[18]=4;
	pos[19]=8;
	time[19]=1;
	pos[20]=8;
	time[20]=2;
	pos[21]=8;
	time[21]=3;
	pos[22]=9;
	time[22]=1;
	pos[23]=9;
	time[23]=2;
	pos[24]=9;
	time[24]=3;
	pos[25]=9;
	time[25]=4;
	string s;
	while(cin>>s){
		int res=0;
		int pre=-1;
		for(int i=0;i<s.size();i++){
			int ii=s[i]-'a';
			res+=time[ii];
			if(pos[ii]==pre) res+=2;
			pre=pos[ii];
		}
		cout<<res<<endl;
	}
}

整数拆分1

题目描述
一个整数总可以拆分为2的幂的和,例如: 7=1+2+4 7=1+2+2+2 7=1+1+1+4 7=1+1+1+2+2 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 总共有六种不同的拆分方式。 再比如:4可以拆分成:4 = 4,4 = 1 + 1 + 1 + 1,4 = 2 + 2,4=1+1+2。 用f(n)表示n的不同拆分的种数,例如f(7)=6. 要求编写程序,读入n(不超过1000000),输出f(n)%1000000000。
输入描述:
每组输入包括一个整数:N(1<=N<=1000000)。
输出描述:
对于每组数据,输出f(n)%1000000000。
示例1 
输入
复制
7
输出
复制
6

题目的意思是将整数n拆分成2的幂,一共有多少种拆分方法,思路为动态规划,那么关键就是递归方程如何写!!

考虑以下情况

  • n为奇数时,可以拆分的情况之后在n-1的拆分情况上加1,即 f(n)=f(n-1)
  • n为偶数时,对n进行拆分,按照可不可以拆分出1划分
    • 可以拆分出1,f(n-1)
    • 不可以拆分出1,也就是将n/2拆分的结果每个乘2,即f(n/2)
    • f(n)=f(n-1)+f(n/2)
  • 起始为 f(0)=0,f(1)=1,f(2)=2
#include<stdio.h>
int main(){
    int dp[1000001],num,i;
    dp[0]=0;
    dp[1]=1;
    dp[2]=2;
    for(i=3;i<=1000000;i++){
        dp[i]=0;
        if(i&1)
            dp[i]=(dp[i-1])%1000000000;
        else
            dp[i]=(dp[i-1]+dp[i/2])%1000000000;
    }
    while(scanf("%d",&num)!=EOF)
        printf("%d\n",dp[num]);
}

关于数组分配的空间是不是太大这个问题很玄学


数字拆分2

这道题为看到的另一个经典的动态规划题目

输入n,k;输出将n拆分为最大值为k的组合的个数

如n=5,k=5时输出结果为5

思路如下

  • 当n=k时,f(n,k)=f(n,k-1)+1。加的1时n=k
  • 当n<k时,f(n,k)=f(n,n)
  • 当n>k时,考虑能不能拆分出k
    • f(n,k)=f(n-k,k)+f(n,k-1)
  • 初始条件为 f(1,i)=1,f(i,1)=1
#include<stdio.h>
#include<iostream>
#include<vector>
using namespace std;

int main(){
	int n,k;
	while(cin>>n){
		cin>>k;
		vector<vector <int> > dp(n+1);
		for(int i=0;i<=n;i++){
			dp[i].resize(k+1);
			for(int j=0;j<=k;j++){
				dp[i][j]=0;
				if(j==1) dp[i][j]=1;
				if(i==1) dp[i][j]=1;
			}
		}
		for(int i=2;i<=n;i++){
			for(int j=2;j<=k;j++){
				if(i==j) dp[i][j]=dp[i][j-1]+1;
				else if(i<j) dp[i][j]=dp[i][i];
				else{
					dp[i][j]=dp[i-j][j]+dp[i][j-1];
				}
			}
		}
	}
} 

二叉树遍历

题目描述
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入描述:
输入包括1行字符串,长度不超过100。
输出描述:
可能有多组测试数据,对于每组数据,
输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。
每个输出结果占一行。
示例1 
输入
复制
abc##de#g##f###
输出
复制
c b e g d f a 

根据先序遍历还原二叉树,之后进行中序遍历

因为先序遍历的时候是从根节点开始一直向左下遍历,那么就按照这个顺序构造二叉树,设置全局变量并且传参时使用引用将读取先序遍历的每种情况,如果读到#说明为叶子节点,之后不再添加,使用build函数返回node*

#include<stdio.h>
#include<iostream>
using namespace std;

struct Node{
	char val;
	Node *lchild;
	Node *rchild;
};

Node* build(int &index,string s){
	index++;
	Node * root=new Node();
	char c=s[index];
	if(c=='#'){
		return NULL;
	}
	else{
		root->val=c;
		root->lchild=build(index,s);
		root->rchild=build(index,s);
		return root;
	}
}

void inorder(Node *root){
	if(root==NULL) return;
	inorder(root->lchild);
	cout<<root->val<<" ";
	inorder(root->rchild);
}

int main(){
	string s;
	while(cin>>s){
		int index=-1;
		Node* root;
		root=build(index,s);
		inorder(root);
		cout<<endl;
	}
}

玛雅人的密码

玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串,(2=<N<=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。
输入描述:
输入包含多组测试数据,每组测试数据由两行组成。
第一行为一个整数N,代表字符串的长度(2<=N<=13)。
第二行为一个仅由0、1、2组成的,长度为N的字符串。
输出描述:
对于每组测试数据,若可以解出密码,输出最少的移位次数;否则输出-1。
示例1 
输入
复制
5
02120
输出
复制
1

对题目简单分析之后是搜索问题,如果用深度优先搜索实现困难,没想到具体要怎么实现,由于又是要求最优解,所以使用广度优先搜索对结果进行搜索,状态为移位的次数。另外,存储已经被扩展过的字符串,如果再次出现不再扩展,剪枝。

判断是否是包含字符串使用有限状态机。

#include<iostream>
#include<stdio.h>
#include<queue>
#include<map>
using namespace std;

//广度优先搜索吗
struct R{
	string s;
	int change=0; //交换的次数 
}; 

bool ispass(R r){
	int state=0;
	for(int i=0;i<r.s.size();i++){
		switch(state){
			case 0:
				if(r.s[i]=='2')
					state=1;
				break;
			case 1:
				if(r.s[i]=='0')
					state=2;
				else
					state=0;
				break;
			case 2:
				if(r.s[i]=='1')
					state=3;
				else
					state=0;
				break;
			case 3:
				if(r.s[i]=='2')
					return true;
				else
					state=0;
				break;
		}
	}
	return false;
}


int main(){
	int n;
	while(cin>>n){
		queue<R> que;
		map<string,int> exist;
		R r;
		int res=1001;
		cin>>r.s;
		
		int count1=0;
		int count0=0;
		int count2=0;
		for(int i=0;i<r.s.size();i++){
			if(r.s[i]=='0')
				count0++;
			else if(r.s[i]=='1')
				count1++;
			else if(r.s[i]=='2')
				count2++;
		}
		if(count1<1||count0<1||count2<2){
			cout<<"-1"<<endl;
			continue;
		}
		que.push(r);
		if(ispass(r)){
			cout<<"0"<<endl;
			continue;
		}
		while(!que.empty()){	 
			R tmp2;
			tmp2=que.front();
			que.pop();
			for(int i=0;i<tmp2.s.size()-1;i++){
				string tmp3;
				for(int j=0;j<tmp2.s.size();j++)
					tmp3.push_back(tmp2.s[j]);
				char tmp4=tmp3[i];
				tmp3[i]=tmp3[i+1];
				tmp3[i+1]=tmp4;
				if(exist.find(tmp3)==exist.end()){
//					cout<<tmp3<<endl;
					exist[tmp3]=1;
					R tmp5;
					tmp5.s=tmp3;
					tmp5.change=tmp2.change+1;
					if(ispass(tmp5)){
						res=min(res,tmp5.change);
					}
					else{
						que.push(tmp5);
					}
				}
			}
		}
		if(res>1000){
			cout<<"-1"<<endl;
		}
		else{
			cout<<res<<endl;
		}
	}
}

最小邮票数

题目描述
    有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。     如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。
输入描述:
    有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。
输出描述:
      对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。
示例1 
输入
复制
10
5
1 3 3 3 4
输出
复制
3

要求正好装满的01背包问题

#include<iostream>
#include<vector>
using namespace std;

int main(){
	int m,n;  //邮票总价值,邮票的数量
	while(cin>>m){
		cin>>n;
		vector<int> stamp(n);
		for(int i=0;i<n;i++)
			cin>>stamp[i];
		vector<int> dp(m+1,100001);
		dp[0]=0;
//		cout<<"1:"<<endl;
		for(int i=0;i<n;i++){
			for(int j=m;j>=stamp[i];j--){
				dp[j]=min(dp[j],dp[j-stamp[i]]+1);
			}
		}
		if(dp[m]==100001)
			cout<<"0"<<endl;
		else
			cout<<dp[m]<<endl;
	} 
} 

abc

题目描述
设a、b、c均是0到9之间的数字,abc、bcc是两个三位数,且有:abc+bcc=532。求满足条件的所有a、b、c的值。
输入描述:
题目没有任何输入。
输出描述:
请输出所有满足题目条件的a、b、c的值。
a、b、c之间用空格隔开。
每个输出占一行。
#include<iostream>
using namespace std;

int main(){
	for(int a=0;a<10;a++){
		for(int b=0;b<10;b++){
			for(int c=0;c<10;c++){
				if(100*a+110*b+12*c==532){
					cout<<a<<" "<<b<<" "<<c<<endl;
				}
			}
		}
	}
}

root(N,k)

题目描述
    N<k时,root(N,k) = N,否则,root(N,k) = root(N',k)。N'为N的k进制表示的各位数字之和。输入x,y,k,输出root(x^y,k)的值 (这里^为乘方,不是异或),2=<k<=16,0<x,y<2000000000,有一半的测试点里 x^y 会溢出int的范围(>=2000000000) 
输入描述:
    每组测试数据包括一行,x(0<x<2000000000), y(0<y<2000000000), k(2<=k<=16)
输出描述:
    输入可能有多组数据,对于每一组数据,root(x^y, k)的值
示例1 
输入
复制
4 4 10
输出
复制
4

快速幂除法:求a^b%c 时对a和b分别降低,另外由于即使知道了大整数除法不会溢出的方法,也不能快速求出答案,所以对关系式进行推导

#include<iostream>
#include<math.h>
using namespace std;

long long root(long long x,long long y,long long k){
	long long res=1;
//	x=x%k;
	while(y){
		if(y&1) res=(res*x)%k;
		x=(x*x)%k;
		y=y>>1;
	} 
	return res;
}

int main(){
	long long x,y,k,res;
	while(cin>>x){
		cin>>y;
		cin>>k;
		res=root(x,y,k-1);
		if(res==0) cout<<k-1<<endl;
		else cout<<res<<endl;
	}
} 

n的阶乘


特殊乘法

题目描述
写个算法,对2个小于1000000000的输入,求结果。 特殊乘法举例:123 * 45 = 1*4 +1*5 +2*4 +2*5 +3*4+3*5
输入描述:
两个小于1000000000的数
输出描述:
输入可能有多组数据,对于每一组数据,输出Input中的两个数按照题目要求的方法进行运算后得到的结果。
示例1 
输入
复制
123 45
输出
复制
54
#include<iostream>
#include<vector> 
using namespace std;

int main(){
	string a,b;
	while(cin>>a){
		cin>>b;
		vector<int> aa;
		vector<int> bb;
		for(int i=0;i<a.size();i++){
			aa.push_back(a[i]-'0');
		}
		for(int i=0;i<b.size();i++){
			bb.push_back(b[i]-'0');
		}
		int res=0;
		for(int i=0;i<aa.size();i++){
			for(int j=0;j<bb.size();j++){
				res+=aa[i]*bb[j];
			}
		}
		cout<<res<<endl;
	}
}

今年的第几天

题目描述
输入年、月、日,计算该天是本年的第几天。
输入描述:
包括三个整数年(1<=Y<=3000)、月(1<=M<=12)、日(1<=D<=31)。
输出描述:
输入可能有多组测试数据,对于每一组测试数据,
输出一个整数,代表Input中的年、月、日对应本年的第几天。
示例1 
输入
复制
1990 9 20
2000 5 1
输出
复制
263
122
#include<iostream>
using namespace std;

bool isrun(int year){
	if((year%4==0&&year%100!=0)||(year%400)==0) return true;
	else return false;
}

int main(){
	int days[12][2]={
	{31,31},
	{28,29},
	{31,31},
	{30,30},
	{31,31},
	{30,30},
	{31,31},
	{31,31},
	{30,30},
	{31,31},
	{30,30},
	{31,31},
	};
	
	int year,month,day;
	while(cin>>year){
		cin>>month;
		cin>>day;
		int index=0;
		if(isrun(year)) index=1;
		int res=0;
		for(int i=0;i<month-1;i++){
//			cout<<"add:"<<days[index][i]<<endl; 
			res+=days[i][index];
		}
		res+=day;
		cout<<res<<endl;
		
	}
}

完数vs盈数

题目描述
一个数如果恰好等于它的各因子(该数本身除外)子和,如:6=3+2+1。则称其为“完数”;若因子之和大于该数,则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。
输入描述:
题目没有任何输入。
输出描述:
输出2到60之间所有“完数”和“盈数”,并以如下形式输出:
E: e1 e2 e3 ......(ei为完数)
G: g1 g2 g3 ......(gi为盈数)
其中两个数之间要有空格,行尾不加空格。
#include<iostream>
#include<vector>
using namespace std;

int main(){
	vector<int> E;  //完数 
	vector<int> G;  //盈数
	for(int i=2;i<=60;i++){
		int tmp=0;
		for(int j=1;j<i;j++){
			if(i%j==0) tmp+=j;
		}
		if(tmp==i) E.push_back(i);
		else if(tmp>i) G.push_back(i);
	} 
	cout<<"E:";
	for(int i=0;i<E.size();i++){
		cout<<" "<<E[i];
	}
	cout<<endl;
	cout<<"G:";
	for(int i=0;i<G.size();i++){
		cout<<" "<<G[i];
	}
	cout<<endl;
}

最大序列和

题目描述
给出一个整数序列S,其中有N个数,定义其中一个非空连续子序列T中所有数的和为T的“序列和”。 对于S的所有非空连续子序列T,求最大的序列和。 变量条件:N为正整数,N≤1000000,结果序列和在范围(-2^63,2^63-1)以内。
输入描述:
第一行为一个正整数N,第二行为N个整数,表示序列中的数。
输出描述:
输入可能包括多组数据,对于每一组输入数据,
仅输出一个数,表示最大序列和。
示例1 
输入
复制
5
1 5 -3 2 4

6
1 -2 3 4 -10 6

4
-3 -1 -2 -5
输出
复制
9
7
-1
#include<iostream>
using namespace std;

int main(){
	int n;
	while(cin>>n){
		int tmp;
		cin>>tmp;
		int cur=tmp;
		int maxx=tmp;
		n--;
		while(n--){
			cin>>tmp;
			if(cur+tmp>tmp){
				cur=cur+tmp;
			}
			else{
				cur=tmp;
			}
			maxx=max(cur,maxx);
		}
		cout<<maxx<<endl;
	}
}

最小花费

题目描述
在某条线路上有N个火车站,有三种距离的路程,L1,L2,L3,对应的价格为C1,C2,C3.其对应关系如下: 距离s           票价 0<S<=L1         C1 L1<S<=L2        C2 L2<S<=L3        C3 输入保证0<L1<L2<L3<10^9,0<C1<C2<C3<10^9。 每两个站之间的距离不超过L3。 当乘客要移动的两个站的距离大于L3的时候,可以选择从中间一个站下车,然后买票再上车,所以乘客整个过程中至少会买两张票。 现在给你一个 L1,L2,L3,C1,C2,C3。然后是A B的值,其分别为乘客旅程的起始站和终点站。 然后输入N,N为该线路上的总的火车站数目,然后输入N-1个整数,分别代表从该线路上的第一个站,到第2个站,第3个站,……,第N个站的距离。 根据输入,输出乘客从A到B站的最小花费。
输入描述:
以如下格式输入数据:
L1  L2  L3  C1  C2  C3
A  B
N
a[2]
a[3]
……
a[N]
输出描述:
可能有多组测试数据,对于每一组数据,
根据输入,输出乘客从A到B站的最小花费。
示例1 
输入
复制
1 2 3 1 2 3
1 2
2
2
输出
复制
2

动态规划,和建广告牌那个题差不多

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

struct LC{
	int l;
	int c;
	bool operator < (const LC &lc) const{
		if(c/l==lc.c/lc.l) return c<lc.c;
		else return c/l<lc.c/lc.l;
	}
}; 

int main(){
	int tmp,a,b,n;
	while(cin>>tmp){
//		LC lc[3];
		vector<LC> lc(3);

		lc[0].l=tmp;
		cin>>lc[1].l;
		cin>>lc[2].l;
		cin>>lc[0].c;
		cin>>lc[1].c;
		cin>>lc[2].c;
		sort(lc.begin(),lc.begin()+lc.size());
		cin>>a;
		cin>>b;
		cin>>n;
		vector<int> dis(n+1);
		vector<int> res(n+1);
		for(int i=0;i<=n;i++){
			res[i]=1000000000;
		}
		res[a]=0;
		for(int i=2;i<=n;i++){
			cin>>dis[i];
		}
		dis[1]=0;
		for(int i=a+1;i<=b;i++){  //到达每一个站的最小花费 
			for(int j=a;j<i;j++){
				int distance=dis[i]-dis[j];
//				cout<<"dis:"<<distance<<endl;
				for(int k=0;k<lc.size();k++){
					if(lc[k].l>=distance){
						res[i]=min(res[i],res[j]+lc[k].c);
					}
				}
			}
		}
		cout<<res[b]<<endl; 
	}
}

N的阶乘

题目描述
 输入一个正整数N,输出N的阶乘。
输入描述:
正整数N(0<=N<=1000)
输出描述:
 输入可能包括多组数据,对于每一组输入数据,输出N的阶乘
示例1 
输入
复制
4
5
15
输出
复制
24
120
1307674368000
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;

string add(string a,string b){
	string res;
	int car=0;
	int lena=a.size();
	int lenb=b.size();
	int len=min(lena,lenb);
	int ai,bi;
	for(ai=lena-1,bi=lenb-1;len>0;len--,ai--,bi--){
		int aa=a[ai]-'0';
		int bb=b[bi]-'0';
		int tmp=(aa+bb+car)%10;
		car=(aa+bb+car)/10;
		res.insert(res.begin(),tmp+'0');
	}
	if(lena==lenb){
		if(car!=0){
			res.insert(res.begin(),car+'0');
		}
		return res;
	}
	else if(lena<lenb){
		for(int i=bi;i>=0;i--){
			int tmp=((b[i]-'0')+car)%10;
			car=((b[i]-'0')+car)/10;
			res.insert(res.begin(),tmp+'0');
		}
		if(car!=0){
			res.insert(res.begin(),car+'0');
		}
		return res;
	}
	else if(lenb<lena){
		for(int i=ai;i>=0;i--){
			int tmp=((a[i]-'0')+car)%10;
			car=((a[i]-'0')+car)/10;
			res.insert(res.begin(),tmp+'0');
		}
		if(car!=0){
			res.insert(res.begin(),car+'0');
		}
		return res;
	}
}

string mul(string a,string b){
	string res="0";
	if(a=="0"||b=="0") return res;
	int lena=a.size();
	int lenb=b.size();
	int zero=0;
	for(int bi=lenb-1;bi>=0;bi--){
		int car=0;
		string rest;
		for(int ai=lena-1;ai>=0;ai--){
			int aa=a[ai]-'0';
			int bb=b[bi]-'0';
			int tmp=aa*bb+car;
			rest.insert(rest.begin(),tmp%10+'0');
			car=tmp/10;
		}
		if(car!=0) rest.insert(rest.begin(),car+'0');
		for(int i=0;i<zero;i++){
			rest.push_back('0');
		}
		zero++;
		res=add(res,rest);
	}
	return res;
}
/*
string to_string2(int n){
	if(n==0) return "0";
	else{
		string res;
		while(n!=0){
			res.insert(res.begin(),n%10+'0');
			n=n/10;
		}
		return res;
	}
}*/

string jiecheng(int n){
	if(n==0) return "1";
	string res=to_string(n);
	for(int i=n-1;i>0;i--){
		res=mul(res,to_string(i));
	} 
	return res;
}

int main(){
	int a;
	while(cin>>a){
		cout<<jiecheng(a)<<endl;
	}
}

剩下的树

题目描述
    有一个长度为整数L(1<=L<=10000)的马路,可以想象成数轴上长度为L的一个线段,起点是坐标原点,在每个整数坐标点有一棵树,即在0,1,2,...,L共L+1个位置上有L+1棵树。     现在要移走一些树,移走的树的区间用一对数字表示,如 100 200表示移走从100到200之间(包括端点)所有的树。     可能有M(1<=M<=100)个区间,区间之间可能有重叠。现在要求移走所有区间的树之后剩下的树的个数。
输入描述:
    两个整数L(1<=L<=10000)和M(1<=M<=100)。
    接下来有M组整数,每组有一对数字。
输出描述:
    可能有多组输入数据,对于每组输入数据,输出一个数,表示移走所有区间的树之后剩下的树的个数。
示例1 
输入
复制
500 3
100 200
150 300
470 471
输出
复制
298

10进制vs2进制

题目描述
    对于一个十进制数A,将A转换为二进制数,然后按位逆序排列,再转换为十进制数B,我们乘B为A的二进制逆序数。     例如对于十进制数173,它的二进制形式为10101101,逆序排列得到10110101,其十进制数为181,181即为173的二进制逆序数。
输入描述:
    一个1000位(即10^999)以内的十进制数。
输出描述:
    输入的十进制数的二进制逆序数。
示例1 
输入
复制
173
输出
复制
181

查找学生信息

题目描述
输入N个学生的信息,然后进行查询。
输入描述:
输入的第一行为N,即学生的个数(N<=1000)
接下来的N行包括N个学生的信息,信息格式如下:
01 李江 男 21
02 刘唐 男 23
03 张军 男 19
04 王娜 女 19
然后输入一个M(M<=10000),接下来会有M行,代表M次查询,每行输入一个学号,格式如下:
02
03
01
04
输出描述:
输出M行,每行包括一个对应于查询的学生的信息。
如果没有对应的学生信息,则输出“No Answer!”
示例1 
输入
复制
4
01 李江 男 21
02 刘唐 男 23
03 张军 男 19
04 王娜 女 19
5
02
03
01
04
03
输出
复制
02 刘唐 男 23
03 张军 男 19
01 李江 男 21
04 王娜 女 19
03 张军 男 19

函数求值

题目描述
给定正整数N,函数F(N)表示小于等于N的自然数中1和2的个数之和,例如:1,2,3,4,5,6,7,8,9,10序列中1和2的个数之和为3,因此 F(10)=3。输入N,求F(N)的值,1=<N<=10^100(10的100次方)若F(N)很大,则求F(N)mod20123的值 

输入描述:
无
输出描述:
无
示例1 
输入
复制
10
10
输出
复制
3
3
#include<iostream>
using namespace std;

int main(){
	string str;
	while(cin>>str){
		int len=str.length();
		int result=0,count=0,num=0;
		for(int i=0;i<len;i++){
			int temp=str[i]-'0';
			result=((result-count)*10+num*2+count*(temp+1)+min(temp,2))%20123;
			num=(num*10+temp)%20123;
			if(temp==1||temp==2){
				++count;
			}
		}
		cout<<result<<endl;
	}
	return 0;
}

参考内容:https://blog.youkuaiyun.com/qq_38341682/article/details/88647619

对数据进行找规律,从F(1),F(12),F(123),F(1234)逐渐递推

F(123)中1,2的个数为result,count为123中1,2的个数,num为123,也就是1234之间间隔了多少个10,temp为最后一位的数

(result-count)*10 表示122x中1,2的个数,不包括各位

num*2 表示122x中个位上1,2的个数 

count*(temp+1)表示123x中1,2的个数,不包括个位

min(temp,2)表示123x中个位上1,2的个数


进制转化2

题目描述
将M进制的数X转换为N进制的数输出。
输入描述:
输入的第一行包括两个整数:M和N(2<=M,N<=36)。
下面的一行输入一个数X,X是M进制的数,现在要求你将M进制的数X转换成N进制的数输出。
输出描述:
输出X的N进制表示的数。
示例1 
输入
复制
10 2
11
输出
复制
1011
备注:
注意输入时如有字母,则字母为大写,输出时如有字母,则字母为小写。
#include<iostream>
using namespace std;

int main(){
	int m,n;
	string x;
	while(cin>>m){
		cin>>n;
		cin>>x;
		long long tmp=0;
		int cur=0;
		for(int i=0;i<x.length();i++){
			if(x[i]>='0'&&x[i]<='9'){
				cur=x[i]-'0';
			}
			else if(x[i]<='Z'&&x[i]>='A'){
				cur=10+x[i]-'A';
			}
			tmp=tmp*m+cur;
		}
//		cout<<"temp:"<<tmp<<endl;
		string res;
		int rmd=0;
		while(tmp!=0){
			rmd=tmp%n;
			if(rmd<10){
				res.insert(res.begin(),rmd+'0');
				tmp=tmp/n;
			}
			else{
				res.insert(res.begin(),rmd-10+'a');
				tmp=tmp/n;
			}
		}
		cout<<res<<endl;
		
	}
}

反序数

题目描述
设N是一个四位数,它的9倍恰好是其反序数(例如:1234的反序数是4321)
求N的值
输入描述:
程序无任何输入数据。
输出描述:
输出题目要求的四位数,如果结果有多组,则每组结果之间以回车隔开。
示例1 
输入
复制
无
输出
复制
无
#include<iostream>
#include<algorithm> 
using namespace std;

int main(){
	string a,b;
	for(int i=1000;i<1112;i++){
		a=to_string(i);
		b=to_string(i*9);
		if(b.length()!=4) continue;
		reverse(b.begin(),b.end());
		bool flag=true;
		for(int i=0;i<a.length();i++){
			if(a[i]!=b[i]){
				flag=false;
				break;
			} 
		}
		if(flag){
			cout<<a<<endl;
		}
	}
}

完全平方数

题目描述
打印所有不超过256,其平方具有对称性质的数。如2,11就是这样的数,因为2*2=4,11*11=121。
输入描述:
无任何输入数据
输出描述:
输出具有题目要求的性质的数。如果输出数据不止一组,各组数据之间以回车隔开。
示例1 
输入
复制
无
输出
复制
无
#include<iostream>
using namespace std;

int main(){
    for(int i=0;i<=256;i++){
        string a=to_string(i*i);
        int begin=0;
        int end=a.size()-1;
        bool flag=true;
        while(begin<=end){
            if(a[begin]==a[end]){
                begin++;
                end--;
            }
            else{
                flag=false;
                break;
            }
        }
        if(flag){
            cout<<i<<endl;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值