基础向算法题练习2

双进制回文数

十进制数585 = 10010010012(二进制表示),因此它在这两种进制下都是回文数。
找出所有小于一百万,且在十进制和二进制下均回文的数,并求它们的和。
(请注意,无论在哪种进制下,回文数均不考虑前导零。)

#include<iostream>
/**
	数学问题了 
 */ 
using namespace std;
int check(int x,int n){
	int raw=x,t=0;
	while(x){            //经典反转了 n 是进制数
		t=t*n+x%n;
		x/=n;
	}
	return t==raw;
}

int main(){
	int ans=0;
	for(int i=1;i<1000000;i++){
		if(check(i,10)&&check(i,2)){
			ans+=i;
			cout<<i<<endl;
		}
	}
	cout<<ans<<endl;
	return 0;
}

数塔狂想曲

相信大家都学过树塔问题,题目很简单求最大化一个三角形数塔从上往下走的路径和。走的规则是:(i,j)(i,j) 号点只能走向 (i+1,j)(i+1,j) 或者 (i+1,j+1)(i+1,j+1)。如下图是一个数塔,映射到该数塔上行走的规则为:从左上角的点开始,向下走或向右下走直到最底层结束。
1
3 8
2 5 0
1 4 3 8
1 4 2 5 0
​ 路径最大和是 1+8+5+4+4=221+8+5+4+4=22,1+8+5+3+5=221+8+5+3+5=22 或者 1+8+0+8+5=221+8+0+8+5=22。
​ 小 SS 觉得这个问题 so easyso easy。于是他提高了点难度,他每次 banban 掉一个点(即规定哪个点不能经过),然后询问你不走该点的最大路径和。当然他上一个询问被 banban 掉的点过一个询问会恢复(即每次他在原图的基础上 banban 掉一个点,而不是永久化的修改)。

输入
​ 第一行包括两个正整数 N,MN,M 分别表示数塔的高和询问次数。
​ 以下 NN 行,第 ii 行包括用空格隔开的 i−1i−1 个数,描述一个高为 NN 的数塔。
​ 而后 MM 行,每行包括两个数 X,YX,Y,表示第 XX 行第 YY 列的数塔上的点被小 SS banban 掉,无法通行。
​ (由于读入数据较大,请使用较为快速的读入方式)
输出
​ MM 行每行包括一个非负整数,表示在原图的基础上 banban 掉一个点后的最大路径和,如果被 banban 掉后不存在任意一条路径,则输出 −1−1。

样例输入
5 3
1
3 8
2 5 0
1 4 3 8
1 4 2 5 0
2 2
5 4
1 1
样例输出
17
22
-1
样例说明
第一次:
1
3 X
2 5 0
1 4 3 8
1 4 2 5 0
1+3+5+4+4 = 17 或者 1+3+5+3+5=17
第二次:
1
3 8
2 5 0
1 4 3 8
1 4 2 X 0
1+8+5+4+4 = 22
第三次:无法通行,-1!

/**
暴力算的话题目计算高达500000次算了算了
之前数塔问题的升级 删除的点是上下重合的把两边都算一下减一下就好 
*/
#include<iostream>
#include<cstdio>//
using namespace std;
int n,m,num[1005][1005],utd[1005][1005],dtu[1005][1005],ans[1005][1005],mmax[1005][2];
//原始数据,上去下,下去上 ,最大合,最大值和次大值 
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			scanf("%d",&num[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			utd[i][j]=max(utd[i-1][j-1],utd[i-1][j])+num[i][j];	
		}
	} 
	for(int i=n;i>0;i--){
		for(int j=1;j<=i;j++){
			dtu[i][j]=max(dtu[i+1][j],dtu[i+1][j+1])+num[i][j];	
		}
	} 
	for(int i=1;i<=n;i++){ //初始化每个经过最大点的最大合 
		for(int j=1;j<=i;j++){
			ans[i][j]=utd[i][j]+dtu[i][j]-num[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		int m2=0,m1=0,cnt=0;
		for(int j=1;j<=i;j++){
			if(ans[i][j]>m1){ 
				m2=m1;
				m1=ans[i][j];
				cnt=j;
			}else if(m2<ans[i][j]){  //防一手来就是最大的 
				m2=ans[i][j];
			}
			
		}
		mmax[i][0]=cnt;
		mmax[i][1]=m2;
	}
	for(int i=0;i<m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		if(a==1&&b==1){
			printf("-1\n");
		}else if(mmax[a][0]==b){
			printf("%d\n",mmax[a][1]);
		}else{
			printf("%d\n",dtu[1][1]);
		}
	}
	return 0;
}

消去数字的分数

49/98是一个有趣的分数,因为缺乏经验的数学家可能在约简时错误地认为,等式49/98 = 4/8之所以成立,是因为在分数线上下同时抹除了9的缘故。
我们也会想到,存在诸如30/50 = 3/5这样的平凡解。
这类有趣的分数恰好有四个非平凡的例子,它们的分数值小于1,且分子和分母都是两位数。
将这四个分数的乘积写成最简分数,求此时分母的值。

#include<iostream>
/**
	题目说是两位数直接有范围了,枚举就完事 。
	十字相乘来判断 
 */ 
using namespace std;
int check(int a,int b){
	int x1=a/10,x2=a%10;
	int y1=b/10,y2=b%10;
	if(!x1||!x2||!y1||!y2)return 0;
	if(x1==y1&&a*y2==b*x2)return 1;
	if(x1==y2&&a*y1==b*x2)return 1;
	if(x2==y1&&a*y2==b*x1)return 1;
	if(x2==y2&&a*y1==b*x1)return 1;
	return 0;
}
int gcd(int a,int b){ //辗转相除公倍数 
	if(!b)return a;
	return gcd(b,a%b);
}
int main(){
	int a=1,b=1;
	for(int i=11;i<100;i++){
		for(int j=i+1;j<100;j++){
			if(check(i,j)){
				a*=i;
				b*=j;
				cout<<i<<" / " <<j<<endl;
			}
		}
	} 
	int c=gcd(a,b);
	cout<<b/c<<endl; //最简化 
	return 0;
}```




# 各位数字的五次幂
各位数字的五次幂令人惊讶的是,只有三个数可以写成它们各位数字的四次幂之和:
1634 = 14 + 64 + 34 + 44
8208 = 84 + 24 + 04 + 84
9474 = 94 + 44 + 74 + 44
由于1 = 14不是一个和,所以这里并没有把它包括进去。
这些数的和是1634 + 8208 + 9474 = 19316。
找出所有可以写成它们各位数字的五次幂之和的数,并求这些数的和。

```cpp
#include<iostream> 
using namespace std;
/**
	本题没有太大难点关键就是要估计它的界限是多少。 
 */
 int num[10]; 
int init( ){
	for(int i=1;i<10;i++){
		int t=i;
		for(int j=1;j<5;j++){
			t*=i;
		}
		num[i]=t;
	}
}
int check(int x){
	int raw=x,t=0;
	while(x){
		t+=num[x%10];
		x/=10;
	}	
	return raw==t;
}
int main(){
	init();
	int ans=0;
	for(int i=10;i<1000000;i++){
		if(check(i)){
			ans+=i;
			cout<<i<<endl;
		}
	}
	cout<<ans<<endl;
	return 0;
}

全数字的乘积

如果一个n位数包含了1至n的所有数字恰好一次,我们称它为全数字的;例如,五位数15234就是1至5全数字的。
7254是一个特殊的乘积,因为在等式39 × 186 = 7254中,被乘数、乘数和乘积恰好是1至9全数字的。
找出所有被乘数、乘数和乘积恰好是1至9全数字的乘法等式,并求出这些等式中乘积的和。
注意:有些乘积可能从多个乘法等式中得到,但在求和的时候只计算一次。

#include<iostream>
#include<cmath>
 
/**暴力枚举注意重复就要考虑范围,被乘数数1--100,
	乘数应该考虑成乘完答案是否大于9位
 */ 
using namespace std;
int check(int x,int *num){        //判断之前是否出现过     
	while(x){
		if(num[x%10]==1){
			return 0;
		}
		num[x%10]=1;
		x/=10;
	}
	return 1;
}
int func(int a,int b,int c){     //用于判断重复 
	int num[10]={1};
	if(check(a,num)==0)return 0;
	if(check(b,num)==0)return 0;
	if(check(c,num)==0)return 0;
	return 1;
}
int digit(int x){        //算数值位数的 
	return (int)floor(log10(x))+1;
}
int main(){
	int ans=0,mark[10005]={0}; //mark用于标记 
	for(int i;i<100;i++){
		for(int j=i+1;1;j++){
			int a=digit(i),b=digit(j),c=digit(i*j);
			if(a+b+c==9){
				if(func(i,j,i*j)){
					if(mark[i*j]==0){
						mark[i*j]=1;
						ans+=i*j;	
					}	
					cout<<i<<"*"<<j<<"="<<i*j<<endl;
				}
			}else if(a+b+c>9){
				break;
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

名字打分

在这个46K的文本文件names.txt(右击并选择“目标另存为……”)中包含了五千多个名字。首先将它们按照字母序排列,然后计算出每个名字的字母价值,乘以它在按字母顺序排列后的位置,就算出了这个名字的得分。
例如,按照字母序排列后,位于第938位的名字是COLIN,它的字母价值是3+15+12+9+14=53。因此,COLIN这个名字的得分是938×53=49714。
上述文本文件中,所有名字的得分之和是多少?
这题的文本不粘了,本题不难主要在于处理给出的文本。这个看个人了

#include<iostream>
#include<string>
#include<algorithm> 
using namespace std;
int main(){
	int n=0;
	long long ans=0;
	string name[6000];
	while(cin>>name[n]){
		n++;
	}
	sort(name,name+n);
	for(int i=0;i<n;i++){
		int t-0;
		for(int j=0;j<name[i].size();j++){
			t+=name[i][j]-'A'+1;
		}
		ans+=t*(i+1);
	}
	cout<<ans<<endl;
	return 0;
}```


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值