思路1:map
用map容器把字符串与相应的数字依次对应起来,用两个while循环,第一个while循环读到 ‘+’ 号则结束,即确定第一个整数的值;第二个while循环读到 ‘=’ 号则结束,即确定第二个整数的值,最后把两个整数的值相加起来。
注意num1和num2要初始化为0,否则会导致输出的数很大很大,敲黑板!!!
推荐一篇写得很好的博客:map的详细用法
代码如下:
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
int main()
{
map<string,int> m; //映射
m["zero"]=0;
m["one"]=1;
m["two"]=2;
m["three"]=3;
m["four"]=4;
m["five"]=5;
m["six"]=6;
m["seven"]=7;
m["eight"]=8;
m["nine"]=9;
m["+"]=10;
m["="]=11;
while(1)
{
int num1=0,num2=0,ans;
string str;
while(cin>>str) //依次输入字符串,遇到空格会结束此次输入
{
if(m[str]==10) //遇到'+'号则退出循环
break;
num1=num1*10+m[str];
}
while(cin>>str)
{
if(m[str]==11) //遇到'='号则退出循环
break;
num2=num2*10+m[str];
}
if(num1==0&&num2==0)
break;
ans=num1+num2; //相加
printf("%d\n",ans);
}
}
思路2:字符串处理
用字符串数组把字符串与数字一一对应起来,可以多看几遍,加深对字符串数组运用的理解。
不懂strcmp()函数的看这里:C++标准库字符串函数总结
代码如下:
#include<cstdio>
#include<cstring>
using namespace std;
char a[10][10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
int change(char s[]) //字符串数组用法
{
for(int i = 0; i < 10; i++)
{
if(!strcmp(a[i], s)) //字符串相等
return i;
}
}
int main()
{
char str[10], num[10];
while(1)
{
int a = 0, b = 0;
while(scanf("%s", str) && strcmp(str, "+")) //注意字符串数组的用法
a = a*10+change(str);
while(scanf("%s", str) && strcmp(str, "="))
b = b*10+change(str);
if(!(a+b)) //和为0,即a和b均为0,跳出循环
break;
printf("%d\n", a+b);
}
return 0;
}
思路:
1、左区间可以大于右区间,不影响,坑!!!
2、不需要单独考虑0和1的情况。
3、初始操作数应为1或者说最后一步判定为1时要操作数要+1。
代码1:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int main()
{
int l,r;
while (cin>>l>>r)
{
int m=min(l,r); //不能写成l=min(l,r),这样就影响最大值的判断了
int n=max(l,r);
int num=0,total,t;
for (int i=m;i<=n;i++)
{
t=i;
total=0; //计算每个数的操作数之前记得初始化为0
while(t!=1)
{
if (t&1) // 判断为奇数
{
t=t*3+1;
total++;
}
else if(t^0) // 判断为偶数
{
t=t/2;
total++;
}
}
num=max(num,total);
}
cout<<l<<" "<<r<<" "<<num+1<<endl; //注意结果要+1
}
return 0;
}
代码2:
比赛时的写法,想得比较细,把0和1的情况也考虑了,但其实不需要,代码太冗长了。(不建议采用)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
int l,r;
while(scanf("%d%d",&l,&r)!=EOF)
{
int ans=0;
if(l>r) //右区间大于左区间的情况
{
cout<<l<<" "<<r<<" "; //先输出区间边界
if(r==0&&l==1) //区间[1,0]的情况0种
{
cout<<0<<endl;
}
else if(r==0&&l!=1) //右区间为0,左区间不为0的情况
{
for(int i=r+1;i<=l;i++)
{
int t=i; //暂存
int total=0;
while(t!=1) //不为1则循环
{
if(t%2==0) //偶数时
{
t/=2;
total++;
}
else //奇数时
{
t=t*3+1;
total++;
}
}
ans=max(ans,total); //找出最大操作数
}
cout<<ans+1<<endl; //记得加上1!!!
}
else //左区间不为0,右区间不为1的情况
{
for(int i=r;i<=l;i++)
{
int t=i;
int total=0;
while(t!=1)
{
if(t%2==0)
{
t/=2;
total++;
}
else
{
t=t*3+1;
total++;
}
}
ans=max(ans,total);
}
cout<<ans+1<<endl;
}
}
else //右区间大于左区间的情况
{
if(l==0&&r!=1) //左区间为0,右区间不为0的情况
{
l++; //左区间边界变为1
for(int i=l;i<=r;i++)
{
int t=i;
int total=0; //记得每个数的操作数开始前先初始化为0
while(t!=1)
{
if(t%2==0)
{
t/=2;
total++;
}
else
{
t=t*3+1;
total++;
}
}
ans=max(ans,total);
}
cout<<0<<" "<<r<<" "<<ans+1<<endl;
}
else if(l==0&&r==1) //区间[0,1]的情况
{
cout<<0<<" "<<1<<" "<<0<<endl;
}
else //左区间不为0,右区间不为1的情况
{
for(int i=l;i<=r;i++)
{
int t=i;
int total=0;
while(t!=1)
{
if(t%2==0)
{
t/=2;
total++;
}
else
{
t=t*3+1;
total++;
}
}
ans=max(ans,total);
}
cout<<l<<" "<<r<<" "<<ans+1<<endl;
}
}
}
return 0;
}
思路:
- 遍历序列,累加序列的数,如果序列和小于等于0,则从下一位重新累加,同时暂存起始点,如果大于0,则继续累加。
- 在每次循环里,比较子序列和最大值和当前序列和,若当前序列和大于最大值,则重新记录最大值、起始点和终止点。
- 注意,测试样例里有组全为负数的例子,此时序列和为0,起始点终止点就是序列起始点终止点。所以用一个计数器记录负数数量,若等于序列数目,则为该情况。
- 本场比赛第二次因为计数器没有初始化为0而导致WA,再次敲黑板!!!
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==0)
break;
int a[100000],maxn=-100000; //最大值maxn初始化为0
int total=0; //计算子序列和并赋初值0
int l,r,ll; //l表示最大子序列起始点,r表示终止点,ll暂存每段子序列起始点
int num=0; //计算负数的数量并赋初值
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]<0) //计算负数数量
num++;
if(total<=0) //如果子序列和小于等于0,就从下一个数重新累加
{
total=a[i];
ll=a[i]; //暂时存起始点
}
else //如果子序列和大于0,则继续累加
total+=a[i];
if(total>maxn) //如果该段子序列和大于最大值
{
maxn=total; //重新记录最大值
l=ll; //记录起始点
r=a[i]; //记录终止点
}
}
if(num==n) //如果全为负数,则子序列和为0,直接输出起始点和终止点
cout<<0<<" "<<a[1]<<" "<<a[n]<<endl;
else //否则输出最大子序列和,起始点和终止点
cout<<maxn<<" "<<l<<" "<<r<<endl;
}
return 0;
}
思路:
- dfs适合求可行性路径数目,而bfs适合求最短路径之类的(因为一旦搜到,就是最短)
- vis标记该点是否走过,map标记是否有陷阱,结构体q就是走过的点,每个点需要保存自己的坐标和上一个节点的,最终将记录的点输出。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int map[6][6]; //地图
int vis[6][6]; //标记是否走过
int dx[4]={0,0,-1,1}; //横坐标方向
int dy[4]={1,-1,0,0}; //纵坐标方向
struct node
{
int x; //横坐标
int y; //纵坐标
int pre; //前一个点
}q[6*6];
void print(int head)
{
while(q[head].pre!=-1) //当不是起始点时
{
print(q[head].pre); //递归前一个点
printf("(%d, %d)\n",q[head].x,q[head].y);
return;
}
printf("(0, 0)\n"); //输出起始点
}
void bfs(int x,int y)
{
int head=0,tail=1;
q[0].x=0; //起始点
q[0].y=0; //终止点
q[0].pre=-1; //起始点的前一个点
node now;
while(head<tail) //当队列不为空
{
if(q[head].x==4&&q[head].y==4) //如果是终点
{
print(head); //遍历输出
return;
}
for(int i=0;i<4;i++) //遍历搜索方向
{
now.x=q[head].x+dx[i]; //横坐标遍历
now.y=q[head].y+dy[i]; //纵坐标遍历
now.pre=head; //变为前一个点
if(now.x>=0&&now.x<=4&&now.y>=0&&now.y<=4) //如果是边界内
{
if(!map[now.x][now.y]&&!vis[now.x][now.y]) //如果没有陷阱且没走过
{
vis[now.x][now.y]=1; //标记走过
q[tail]=now;
tail++; //同节点遍历
}
}
}
head++; //节点+1,即下一节点
}
}
int main()
{
for(int i=0;i<=4;i++)
{
for(int j=0;j<=4;j++)
scanf("%d",&map[i][j]);
}
memset(vis,0,sizeof(vis)); //全部标记为未走过
bfs(0,0); //从起点开始搜索
return 0;
}
思路:
费马小定理:若 p 是质数, a 与 p 互质,那么 a p − 1 ≡ 1 ( m o d ) p a^{p−1} ≡ 1 (mod) p ap−1≡1(mod)p构造: ( m + n ) p = ( m + n ) ( m o d ) p (m+n)^{p} = (m+n) (mod) p (m+n)p=(m+n)(mod)p所以 m p + n p = ( m + n ) ( m o d ) p m^{p} + n^{p}= (m+n) (mod) p mp+np=(m+n)(mod)p所以在模p下,公式恒成立: ( m + n ) p = m p + n p ( 0 ≤ m , n < p ) (m+n)^{^{p}}=m^{p}+n^{p}(0\leq m,n< p) (m+n)p=mp+np(0≤m,n<p)根据定义的加法运算与乘法运算可以直接运算得出。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int p;
cin>>p;
for(int i=1;i<=p;i++)
{
for(int j=1;j<=p;j++)
{
printf("%d%c",((i-1)+(j-1))%p,j==p?'\n':' ');
}
}
for(int i=1;i<=p;i++)
{
for(int j=1;j<=p;j++)
{
printf("%d%c",((i-1)*(j-1))%p,j==p?'\n':' ');
}
}
}
return 0;
}
思路:
费马大定理:a^n + b^n = c^n 若n大于2则无正整数解。
- n=0的情况,肯定也不存在,不可能有1+1=1的情况。
- n=1的情况,b等于 a,c 等于 a*2 即符合表达式。
- n=2的情况,根据勾股数的性值可得出。
勾股数: a² + b² = c²
- 当a为大于1的奇数 2n+1 时,b = 2n² + 2n ,c = 2n² + 2n + 1
故 n = (a-1)÷2 ,得 b = 2n² + 2n ,c = 2n² +2n +1 - 当a为大于4的偶数 2n 时,b = n² - 1 ,c = n² + 1
故 n = a/2 ,得 b = a²/4 - 1 ,c = a²/4 + 1
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
//费马大定理!!!
int t;
scanf("%d",&t);
while(t--)
{
int n,a;
scanf("%d%d",&n,&a);
if(n==0||n>2)
printf("-1 -1\n");
else if(n==1)
printf("%d %d\n",a,a*2);
else if(n==2)
{
if(a%2!=0)
printf("%d %d\n",(a*a-1)/2,(a*a+1)/2); //公式
else
{
if(a==2) //a==2的情况不存在
printf("-1 -1\n");
else
printf("%d %d\n",a*a/4-1,a*a/4+1);
}
}
}
return 0;
}
思路:注意数组要开大点!
- dp[i][j]表示前i种面值硬币狗造成j美分的方法数。
- dp[4][32800]全部初始化为0,dp[0][0]初始化为1。
- 状态转移方程:dp[i][j] = dp[i-1][j] + dp[i][j-val[i]]
val[i]表示第i种硬币的面值,方程前者表示不选第i种硬币的方法数,后者表示选到第i种硬币构造到 j - val[i] 美元的方法数。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
ll dp[4][32800]; //数组要开大点
int main()
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=3;i++)
{
for(int j=0;j<32785;j++) //j要从0开始
dp[i][j]=dp[i-1][j]+dp[i][j-i];
}
int n;
while(scanf("%d",&n)!=EOF)
printf("%lld\n",dp[3][n]);
return 0;
}
思路:数学题,排列组合
- 如果有1行m列,则总矩形数为 m+(m-1)+(m-2)+…+2+1 = (1+m) × m ÷ 2
- 如果有n行1列,则总矩形数为 n+(n-1)+(n-2)+…+2+1 = (1+n) × n ÷ 2
- 则如果有n行m列,总矩形数为 (1+n) × n ÷ 2 × (1+m) × m ÷ 2
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
printf("%d\n",(1+n)*n/2*(1+m)*m/2);
}
return 0;
}
思路:
- 这道题,对于m,既然是要寻找最接近的素数对,那么只要从m/2往下找,只要一找到素数对就可以输出了,因为一定有一个素数小于等于m/2。
- 然后判断素数的,这里的代码是每输入一个数就遍历判断一次,当然也可以直接遍历一个很大的数,打表。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int isPrime(int x)
{
for(int i=2;i*i<=x;i++) //素数返回1,合数返回0
{
if(x%i==0)
return 0;
}
return 1;
}
int main()
{
int m;
while(scanf("%d",&m)!=EOF)
{
for(int i=m/2;i>1;i--)
{
if(isPrime(i)&&isPrime(m-i)) //是素数对
{
printf("%d %d\n",i,m-i);
break;
}
}
}
return 0;
}