双进制回文数
十进制数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;
}```