这又是不顺的一天,我,又,参加,了,老师布置的比赛,然后,又挂了。
这时我旁边的myc巨佬威胁似的对我说了句,你再哔哔一句,考这么好,我的内心很是无奈,他还不承认自己是巨佬,我的天哪,还扬言要弄死我,还要删我博客,好过分啊,简直了,考试考得好不说,还欺负我,没天理!!!
然后我们回归正题,这是一篇考试总结,所以我们聊聊题目以及其解释和考试感受,以及自己关于考试的一个小结。
第一部分.题目及其解释:
First. Classroom Watch
题面描述:
给出一个正整数 n,现在问存在多少个 x,使得 x在十进制下的每一位之和加上 x 等于 n。
1<=n<=1e9。
解析:
对于每一个数,其实它想要通过计算得到n,我们可以看出其实每一位的累加和是非常小的,最大情况下只有9*9=81。所以,其实可能得到n的数字范围只有n-81~n。其实我们只需要对这些数字进行枚举,统计答案即可,当然,某些数学神仙可能另有仙法,我就省下这些笔墨写下一题了。
下面祭出菜逼的代码。
代码:
#include<bits/stdc++.h>
using namespace std;
vector<int>a;
int main()
{
freopen("num.in","r",stdin);
freopen("num.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=n-100;i<=n;i++)
{
int x=i,s=i;
while(x)s+=(x%10),x=x/10;
if(s==n)a.push_back(i);
}
printf("%d\n",a.size());
if(a.size()!=0)for(int i=0;i<=a.size()-1;i++)printf("%d ",a[i]);
return 0;
}
Second.组合技能
题面描述:
如果想购买A商品,则需要花费A元;如果想买B商品,则需要B元;如果两个一起买,则需要C元。商人非常有头脑,每样商品的利润都是相同的。即假设A商品和B商品的成本为a,b元,则A-a=B-b=C-a-b。
给出A,B,C求出利润,数据保证为正数。
输入第一行一个数T,表示T次询问。
接下来T行,每行三个数A,B,C
输出T行,每行一个数,表示利润。
T <= 100;A,B,C <= 2000。
解析:
通过简单的分析,不难看出A+B-C即为所求,因此这就和A+B problem没有什么区别了。
祭出代码。
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen("combo.in","r",stdin);
freopen("combo.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",a+b-c);
}
return 0;
}
Third.表面积
题面描述:
积木图可以抽象为一个n*m的网格图,其中第(i,j)的位置有A[i][j]个积木。求表面积。
输入第一行两个数n,m,接下来n行每行m个数,表示A[i][j]。
输出一个数,表示表面积。
1<=n,m<=100;1<=a[i][j]<=100;
解析:
对于每一个立方体都有六个面(这不是废话吗),我们只需要计算有几个面是被其他的立方体所遮盖的再用立方体数量6-遮住面数量2(一次遮两个面)即为所求。
祭出代码。
代码:
#include<bits/stdc++.h>
using namespace std;
int a[200][200],sum1,sum2;
int main()
{
freopen("surface.in","r",stdin);
freopen("surface.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
sum1+=a[i][j];
sum2+=min(a[i][j],a[i-1][j])+min(a[i][j],a[i][j-1])+a[i][j]-1;
}
printf("%d",sum1*6-sum2*2);
}
Fourth. 红皇后的旅行
题面描述:
给定一个n*n的棋盘,行和列标号为0,1,2,….,n-1。在棋盘的(i_start,j_start)位置上有一位红皇后,每次红皇后可以往六个方向走,如图所示:
现在红皇后想去(i_end,j_end)点,求最短距离,并且输出一条路径。
显然最短路径有无穷条,请按照以下顺序来搜索:UL, UR, R, LR, LL, L。
如果无解,输出Impossible。
解析:
这就是一个裸的广搜,只需要轻松简单的搜索,顺便记录下路径,就可以轻松的得到答案。好像没什么技术含量,但特别注意的是最终的顺序输出是要求从起点到终点的,即记录的过程需倒叙输出,具体请看代码。
祭出代码。
代码:
#include<bits/stdc++.h>
using namespace std;
const int dy[8]={0,-1,1,2,1,-1,-2},dx[8]={0,-2,-2,0,2,2,0};
const string c[8]={" ","UL ","UR ","R ","LR ","LL ","L "};
struct h
{
int x,y,z;
}q[100020],s,e;
struct hh
{
int x,y,z;
}f[220][220];
bool p[220][220];
int h=1,t;
inline void find(int x,int y)
{
if(f[x][y].x==s.x&&f[x][y].y==s.y)cout<<c[f[x][y].z];
else
{
find(f[x][y].x,f[x][y].y);
cout<<c[f[x][y].z];
}
}
int main()
{
freopen("redqueen.in","r",stdin);
freopen("redqueen.out","w",stdout);
int n;
scanf("%d",&n);
scanf("%d%d%d%d",&s.x,&s.y,&e.x,&e.y);
q[++t]=s;p[s.x][s.y]=1;
while(h<=t)
{
int x=q[h].x,y=q[h].y,z=q[h].z;h++;
for(int i=1;i<=6;i++)
{
int x1=x+dx[i],y1=y+dy[i];
if(x1<0||x1>n-1||y1<0||y1>n-1)continue;
if(!p[x1][y1])
{
q[++t].x=x1,q[t].y=y1,q[t].z=z+1;
f[x1][y1].x=x,f[x1][y1].y=y,f[x1][y1].z=i;
p[x1][y1]=1;
if(x1==e.x&&y1==e.y)
{
printf("%d\n",z+1);
find(x1,y1);
return 0;
}
}
}
}
printf("Impossible");
return 0;
}
Fifth.构造序列
题面描述:
有一个长度为n的序列A,其中A[1]=1,A[n]=x,A[2…n-1]可以是1至k间任意一个正整数。求有多少个不同的序列,使得相邻两个数不同。答案对10^9+7取模。
输入共一行,包含三个数,n,k,x。
输出一个数,表示答案。
3<=n<=1e5;2<=k<=1e5;1<=x<=k;
解析:
我们先构思一个类暴力。
我们设定f[i][j]表示到第i个数,结尾为j的序列个数。
我们很容易想到这样的转移方程:
f[i][j]=f[i-1][1]+...+f[i-1][s] (1<=s<=k且s!=j)
于是就有了这样一段代码(含打表):
for(int i=2;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
f[i%2][j]=0;
for(int l=1;l<=k;l++)
if(l!=j)f[i%2][j]=(f[i%2][j]+f[!(i%2)][l])%mod;
}
for(int j=1;j<=k;j++)
printf("%d ",f[i%2][j]);
puts("");
}
但是这显然支持不了时间复杂度,显然我们需要优化。
通过打表我们发现,其实每次只有两个不同的数字在互相转化,如图为对f数组的打表:
我们可以简单的看出两点,每组数据只有两个数字组成,每组数据至于其上一组数据有关,因此,我们可以通过记录两个数字来互相转化而得到后面的数据。于是就有了以下代码:
for(int i=2;i<=n;i++)
{
long long p=a,q=b;
a=(q*(k-1))%mod,b=((q*(k-2))%mod+p)%mod;
}
祭出总的代码。
代码:
#include<bits/stdc++.h>
using namespace std;
const long long mod=1000000007;
long long a,b;
int main()
{
freopen("construct.in","r",stdin);
freopen("construct.out","w",stdout);
int n,k,x;
scanf("%d%d%d",&n,&k,&x);
a=1;b=0;
for(int i=2;i<=n;i++)
{
long long p=a,q=b;
a=(q*(k-1))%mod,b=((q*(k-2))%mod+p)%mod;
}
if(x==1)printf("%lld",a);
else printf("%lld",b);
}
第二部分.考场状况及感受:
First.读题:
今天的题题意清晰,读起来比较轻松,所以在考试时我只读了两题就开始动手(这好像是不对的,幸好今天的题没什么心机,不然就是致命的)。题意理解没有出错(大概算是万幸了)。所以读题还是顺利的。
Second.做题顺序与时间安排:
正如之前所说,题没什么心机,所以大致按照顺序进行,第一题稍稍多花了一点时间,大约在一小时时完成前三题,第四题花费时间属正常范围,在两小时左右完成。最后一题在考试结束前20分钟完成。时间安排比较紧张,虽然也有富余,但不足以修改较大的错误,容易在最后出现问题,需要适当提速。
Third.做题思路:
第一题:
先跑了暴力,中间走了弯路,最后才发现存在问题,差点彻底完蛋。但最后对于零的情况缺少特判,导致因为要小于-1而死循环然后RE。
第二题:
大概猜了一下,然后那计算器算了一下,竟然对了,默默的验证了一下发现没有问题,于是就稳了。
第三题:
一开始想算三个面然后乘二,但是被第二个样例卡了,改了上面写的写法后对了。
第四题:
思路是正确的,但是因为方位数组打反和倒序输出方案卡了一定的时间。
第五题:
先打了三重循环的暴力,在打表找规律,然后又惊奇的发现只有两个数据在互相迭代(兴奋的要死),然后一波操作省了循环还省了空间( ^ _ ^ )。
Forth.考试感受:
旁边有个神仙gst在半小时AK IOI 干掉了三道题,然后还一脸兴奋,很是影响心情,和考试状态,值得庆幸的是,旁边另一个人是myc,让人心情舒缓了许多。题不是很难,反而有些怕自己的写法会不会太神仙导致原地爆炸,而那些老神仙就考得很高(不过还是题简单的好,祈祷一下明天的题简单点(◕ᴗ◕✿))。
第三部分.小结:
这大概是我比较成功的考试,除了vector的白痴错误大概是很和谐的。同时在考试技巧上依然存在部分问题(如:看题顺序),需要有更合理的安排。同时心态的调整也需要加强(其实还好)。千万小心边界,不要再RE了!!!
下次加油啊啊啊o( ̄▽ ̄)o 。