过程:
总体来说今天的结果考试我个人还是比较满意的,该拿的分都拿到了,但过程很艰辛很曲折。我开始看第一题是十分懵逼的,题目描述的是啥都不知道,因此我就先果断放弃了第一题。看完第二题在纸上列了一下等式,移了一下项就会做了,大概花了十几二十分钟就把程序写好了。写完后看了第三题第一个就想画图,结果画了半天越画越乱——so我有回头看第一题。不管三七二十一先花了一些时间打了一个暴力。打完貌似还有很多时间,我就又去画第三题的图。画了半个多小时还是没画出来让我火死了,so我又去调第一题。我开始看第一题的打表,看了大概10分钟多,终于找出了规律。调好后就又回去死磕第三题画图。磕了我n久突然灵光一闪想到了不用画图,就可以想出来,于是开始写代码。之后就开始磕BFS的第四题。
第一题:
一个正整数n,存在多少个x,使得x在十进制下的每一位之和加上x等于n。(1<=n<=10^9)
本来我是从1枚举到n,后来经过大量枚举(跑了n久)发现x的每一位之和不会大于81(9*9),so x至少大于(n-81),所以不需要从1~n枚举,只需要从n-100枚举到n
#include<bits/stdc++.h>
using namespace std;
int n,a,ans=0,l=0;
int k[1100];
int main()
{
freopen("num.in","r",stdin);
freopen("num.out","w",stdout);
cin>>n;
for(int i=max(1,n-1100);i<n;i++)//各个位上的数和定<81 (-1100是保险起见)
{
a=i; ans=i;
while(a>0)
{
if(ans>n) break;
ans+=a%10;
a/=10;
}
if(ans==n)
l++,k[l]=i;
}
cout<<l<<endl;
for(int i=1;i<=l;i++)
cout<<k[i]<<endl;
return 0;
}
第二题:
买第一个物品需要花费A元,买第二个物品则需要B元,一起买两个物品需要C元,商品的利润都是相同的成本为a,b元,
则A-a=B-b=C-a-b。 给出A,B,C求出利润
∵ A-a=B-b=C-a-b
∴ A-a+a+b=B-b+a+b=C-a-b+a+b
∴ A+b=B+a=C
∴ a=C-B,b=C-A
#include<bits/stdc++.h>
using namespace std;
int t;
int A,B,C,a;
int main()
{
freopen("combo.in","r",stdin);
freopen("combo.out","w",stdout);
cin>>t;
for(int i=1;i<=t;i++)
{
cin>>A>>B>>C;
a=C-B;
cout<<A-a<<endl;
}
return 0;
}
第三题:
积木图可以抽象为一个n*m的网格图,其中第(i,j)的位置有A[i][j]个积木,求表面积。
这题我第一反应就是画图,第二反应也是画图,第三反应还是画图。我画了n久,耗了n久的时间……ヽ(´ー`)ノ(其实这也不能太怪我,毕竟题目描述上有两个图)
现在我灵光一闪,我们来来看看输入样例
把每个数想成一个长方体,先计算出每个长方体的表面积,再计算出每个重叠的面积最后减去重叠的面积即可。
#include<bits/stdc++.h>
using namespace std;
int n,m,sum=0,x,l,r,u,d;
int a[110][110];
int main()
{
freopen("surface.in","r",stdin);
freopen("surface.out","w",stdout);
memset(a,0,sizeof(a));
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j],sum+=4*a[i][j]+2;
if(n==1 && m==1 && a[1][1]==1)
{
cout<<sum<<endl; return 0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
x=a[i][j];
l=a[i][j-1]; r=a[i][j+1];
u=a[i-1][j]; d=a[i+1][j];
sum-=min(x,l)+min(x,r)+min(x,u)+min(x,d);
}
cout<<sum<<endl;
}
第四题:
给定一个n*n的棋盘,行和列标号为0,1,2,….,n-1。在棋盘的(i_start,j_start)位置上有一位红皇后,每次红皇后可以往六个方向走, 现在红皇后想去(i_end,j_end)点,求最短距离,并且输出一条路径。 显然最短路径有无穷条,请按照以下顺序来搜索:UL, UR, R, LR, LL, L。 如果无解,输出Impossible
考试时我看出这是bfs,但我表示我不太会打bfs啊!!!
倒着做bfs,每次记一个前驱,从终点倒着搜回去BFS时先把终点加入队列,然后进行拓展枚举6个方向从x点到终点的最短距离,再开一个数组pre[x],pre[x]存的是6个方向的其中一个,表示在dis[x]最小的情况下,接下来走哪个方向,输出时递归
#include<bits/stdc++.h>
using namespace std;
int n;
int sx,sy,ex,ey;
int vis[500][500],dis[500][500];
int dx[10]={-2,-2,0,2,2,0};
int dy[10]={-1,1,2,1,-1,-2};
string a[8]={"UL","UR","R","LR","LL","L"};
struct o
{
int x,y;
}g[500][500],p,pp;
queue<o> d;
void bfs()
{
for(int i=0;i<=n+100;i++)
for(int j=0;j<=n+100;j++)
dis[i][j]=500000000;
dis[sx][sy]=0; vis[sx][sy]=0;
p.x=sx; p.y=sy;
d.push(p);
while(!d.empty())
{
p=d.front();
d.pop();
vis[p.x][p.y]=0;
for(int i=0;i<6;i++)
{
pp.x=p.x+dx[i]; pp.y=p.y+dy[i];
if(pp.x<0 || pp.x>=n || pp.y>=n || pp.y<0)
continue;
if(dis[p.x][p.y]+1<dis[pp.x][pp.y])
{
dis[pp.x][pp.y]=dis[p.x][p.y]+1;
g[pp.x][pp.y].x=p.x;
g[pp.x][pp.y].y=p.y;
if(!vis[pp.x][pp.y])
{
vis[pp.x][pp.y]=1;
d.push(pp);
}
}
}
}
}
void anss(int rx,int ry,int lx,int ly)
{
if(rx==0 && ry==0) return ;
anss(g[rx][ry].x,g[rx][ry].y,rx,ry);
for(int i=0;i<6;i++)
if(rx+dx[i]==lx && ry+dy[i]==ly)
{
cout<<a[i]<<' ';
break;
}
return ;
}
int main()
{
freopen("redqueen.in","r",stdin);
freopen("redqueen.out","w",stdout);
cin>>n>>sx>>sy>>ex>>ey;
bfs();
if(dis[ex][ey]==500000000)
printf("Impossible\n");
else
{
printf("%d\n",dis[ex][ey]);
anss(ex,ey,0,0);
}
return 0;
}
第四题:
有一个长度为n的序列A,其中A[1]=1,A[n]=x,A[2…n-1]可以是1至k间任意一个正整数。求有多少个不同的序列,使得相邻两个数不同
#include<bits/stdc++.h>
using namespace std;
int n,k,x;
long long m=1000000007;
long long f[110000],l[110000];
//f[i]表示第i个数是x的方案数
//l[i]表示前i个数中a[1]=1的方案数
int main()
{
freopen("construct.in","r",stdin);
freopen("construct.out","w",stdout);
cin>>n>>k>>x;
f[2]=k-1;
for(int i=3;i<n;i++)
f[i]=f[i-1]*(k-1)%m;
//相邻两个不能相同,因此f[i]的位置不能填f[i-1]位置上的数字
if(x==1) l[2]=0;
//相邻两数不相等,而f[1]必须是1,因此x==1时l[2]为0,否则就有一种情况
else l[2]=1;
for(int i=3;i<=n;i++)
l[i]=(f[i-1]-l[i-1]+m)%m;
//前i-1个数共有l[i-1]种方案,而i-1的位置是x的有l[i-1],又因为相邻两数不能相等,因此要减去
cout<<l[n]<<endl;
return 0;
}