今天阳光明媚,万里无云……呃,天空下起了蒙蒙细雨(没有太阳,没有太阳……)。
反正呢就是一大早上要考试。考试从原先说好的普及变成了提高模拟。但是拿到考题的时候呢,好像还是偏普及的难度……
总之差一点点就可以AC前三题……
T1.Classroom Watch「Codeforces Round #441」
【题目描述】
给出一个正整数 n,现在问存在多少个 x,使得 x在十进制下的每一位之和加上 x 等于 n。(1<n<1*10^9)
【输入】
输入一个整数n
【输出】
第一行输出一个整数 m,表示有 m 个符合条件的 (若没有符合条件的 ,请只输出一个 0)。
下面m行,每行一个 x ,x按从小到大输出。
【题解】
做的第一道题不是这一题。因为这一题刚开始做的时候想的是从1~n枚举每一个数,但是觉得效率很低,所以就没有先写。看完所有的题目发现还是第二题比较简单。就先写了第二题。
后来写这一题,因为看到n的大小最大只有1*10^9,所以我觉得可以九重循环枚举每一个数位,然后把组成的数加上数位和,判断是否与n相等就好了。
其实这是一个很暴力的方法,但是我看到考题上面的
瞬间放心了。
但是还是稍微优化了一下
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int s[10000010];
int main()
{
scanf("%d",&n);
int ans=0;
if (n==1000000000)
{
printf("1\n999999932\n");
return 0;
}
bool pp=1;
for (int b=0;b<=9&&pp;b++)
for (int c=0;c<=9&&pp;c++)
for (int d=0;d<=9&&pp;d++)
for (int e=0;e<=9&&pp;e++)
for (int f=0;f<=9&&pp;f++)
for (int g=0;g<=9&&pp;g++)
for (int h=0;h<=9&&pp;h++)
for (int i=0;i<=9&&pp;i++)
for (int j=0;j<=9&&pp;j++)
{
int x=b*100000000+c*10000000+d*1000000+e*100000+f*10000+g*1000+h*100+i*10+j;//将每个数位上的书转化为数字
if (x>=n) pp=0;//如果此时x已经大于n了,那么再枚举下去也不会有解
if (x+b+c+d+e+f+g+h+i+j==n)
{
ans++;
s[ans]=x;
}
}
printf("%d\n",ans);
for (int i=1;i<=ans;i++)
printf("%d\n",s[i]);
fclose(stdin);
fclose(stdout);
return 0;
}
正解也需要枚举,但是不需要枚举这么多。
因为最多只会有十位,所以数字的数位和最大只会有9*9=81,所以从n-100到n枚举就可以了,并不需要枚举这么多。
#include <bits/stdc++.h>
using namespace std;
int a[105], m = 0;
int main()
{
int n;
scanf("%d", &n);
for (int i = max(n - 100, 1) ; i <= n ; ++ i)
{
int Sum = i, x = i;
while (x)
Sum += x % 10, x /= 10;
if (Sum == n)
a[++ m] = i;
}
printf("%d\n", m);
for (int i = 1 ; i <= m ; ++ i)
printf("%d\n", a[i]);
return 0;
}
T2.组合技能
【题目描述】
蓝月商城出新技能书了!!
如果古天乐想购买“旋风斩”,则他需要花费A元;如果古天乐想买“半月弯刀”,则需要B元;如果古天乐两个一起买,则需要C元。
蓝月的设计师非常有头脑,每样商品的利润都是相同的。即假设旋风斩和半月弯刀的成本为a,b元,
则A-a=B-b=C-a-b。
给出A,B,C求出利润,数据保证为正数。
(T <= 100, A,B,C <= 2000)
【输入输出】
输入第一行一个数T,表示T次询问。
接下来T行,每行三个数A,B,C
输出T行,每行一个数,表示利润。
【题解】
因为题目中给了一个等式 A-a=B-b=C-a-b
设A-a=B-b=C-a-b=x
我们将这个式子变形
A = x + a ……①
B = x + b ……②
C=x+a+b ……③
①-②得 b=C-A
x=B-b
=B-(C-A);
所以方法就出来了,因为ABC都是给定的
【代码】
#include<bits/stdc++.h>
using namespace std;
int t;
int main()
{
freopen("combo.in","r",stdin);
freopen("combo.out","w",stdout);
cin>>t;
while (t--)
{
int ans;
int A,B,C;
cin>>A>>B>>C;
ans=B-(C-A);
cout<<ans<<endl;
}
return 0;
}
因为这一题把等式列出来了,为我们提供了思路,所以这一题是比较好写的。
T3.表面积
【题目描述】
古天乐在搭积木,积木图可以抽象为一个n*m的网格图,其中第(i,j)的位置有A[i][j]个积木。求表面积。
格式
输入第一行两个数n,m,接下来n行每行m个数,表示A[i][j]。
输出一个数,表示表面积。
(1<=n,m<=100;1<=a[i][j]<=100)
【题解】
这一题开始的时候想的好复杂,先把从上下左右前后能看到的算出来,再单独算中间因为空缺立方体而多出来的表面积。因为这个缺的这一块可能不只有一块,那么你判断起来就很麻烦,所以一开始并没有写。
后来发现不需要从整体去找缺失的,而是没读入一个平面的位子a[i][j]的时候就可以判断了。
假如(i,j)位子上有a[i][j]个方块
那么从左右方向看,多放这一幢产生的表面积就是abs(a[i][j]-a[i][j-1]);
从前后方向看,多放这一栋产生的表面积是abs(a[i][j]-a[i-1][j]);
所以求出放上每一栋产生的面积总和再加上上下的面积总和就可以了
【代码】
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[110][110];
long long sum,ans;
int main()
{
freopen("surface.in","r",stdin);
freopen("surface.out","w",stdout);
cin>>n>>m;
int sum=n*m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
cin>>a[i][j];
if (a[i][j]==0) sum--;
}
for (int i=1;i<=n+1;i++)
for (int j=1;j<=m+1;j++)
{
ans+=abs(a[i][j-1]-a[i][j]);
ans+=abs(a[i][j]-a[i-1][j]);
}
ans+=sum*2;
cout<<ans<<endl;
return 0;
}
T4.红皇后的旅行
【题目描述】
给定一个n*n的棋盘,行和列标号为0,1,2,….,n-1。在棋盘的(i_start,j_start)位置上有一位红皇后,每次红皇后可以往六个方向走,如图所示:
现在红皇后想去(i_end,j_end)点,求最短距离,并且输出一条路径。
显然最短路径有无穷条,请按照以下顺序来搜索:UL, UR, R, LR, LL, L。
如果无解,输出Impossible
【输入输出】
输入第一行一个数n,第二行四个数,i_start,j_start,i_end,j_end。
输出第一行一个数,最小步数,第二行输出方案。
【题解】
这一题如果不看输出方案,应该是一个很裸 的广搜。所以第一问应该是没有问题的。但是第二问的方案怎么办。我们可以在搜索的时候顺便记录当前状态是从个位子走来的。
#include<bits/stdc++.h>
using namespace std;
int dx[6]={-2,-2,0,2,2,0};
int dy[6]={-1,1,2,1,-1,-2};
string s[6]={"UL","UR","R","LR","LL","L"};
int n;
int sx,sy,ex,ey;
struct hh
{
int x,y;
}pre[222][222];
queue<hh>q;
bool vis[222][222];
int dst[222][222];
void bfs()
{
memset(dst,10,sizeof(dst));
vis[sx][sy]=0;
dst[sx][sy]=0;//dst[x][y]走到x,y的步数
hh l;
l.x=sx;
l.y=sy;
q.push(l);
while (!q.empty())
{
l=q.front();
q.pop();
vis[l.x][l.y]=0;
for (int i=0;i<6;i++)
{
hh ll;
ll.x=l.x+dx[i];
ll.y=l.y+dy[i];
if (ll.x<0||ll.x>=n||ll.y<0||ll.y>=n) continue;
if (dst[l.x][l.y]+1<dst[ll.x][ll.y])
{
dst[ll.x][ll.y]=dst[l.x][l.y]+1;
pre[ll.x][ll.y].x=l.x;//pre[xx][yy].x:xx,yy从x,y走来,记录横坐标x
pre[ll.x][ll.y].y=l.y;//记录纵坐标y;
if (!vis[ll.x][ll.y])
{
vis[ll.x][ll.y]=1;
q.push(ll);
}
}
}
}
}
void dfs(int x,int y,int xx,int yy)
{
if (x==0&&y==0)
return ;
dfs(pre[x][y].x,pre[x][y].y,x,y);
for (int i=0;i<6;i++)
{
if (x+dx[i]==xx&&y+dy[i]==yy)
{
cout<<s[i]<<" ";
break;
}
}
}
int main()
{
freopen("redqueen.in","r",stdin);
freopen("redqueen.out","w",stdout);
scanf("%d",&n);
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
bfs();
if (dst[ex][ey]==168430090)//这么一大串balabala的数字是memset(……,10,sizeof(……))的最大值
{
printf("Impossible\n");
return 0;
}
cout<<dst[ex][ey]<<endl;
dfs(ex,ey,0,0);
return 0;
}
当初做题的时候,面对输出方案毫无思路,所以就只是输出Impossible,和样例,得了45分。
T5.构造序列
【题目描述】
有一个长度为n的序列A,其中A[1]=1,A[n]=x,A[2…n-1]可以是1至k间任意一个正整数。求有多少个不同的序列,使得相邻两个数不同。
答案对10^9+7取模。
这一题……看到的时候觉得很像关于排列组合的。但是左右两端都有数字,有点麻烦
但是这里都有这些限制,所以我的思路很完美的一点都没有。
接下来:
设f[i]表示前i个数中a[1]=1的方案数
** s[i]表示表示第i个数是x的方案数**
f[i]=f[i-1]*(k-1)%kk:相邻两个不能相同,因此a[i]的位置不能填a[i-1]位置上的数字
if (x==1) s[2]=0;
else s[2]=1;相邻两数不相等,而a[1]必须是1,因此x==1时ans[2]为0,否则就有一种情况
s[i]=(f[i-1]-s[i-1]+kk)%kk:前i-1个数共有f[i-1]种方案,而i-1的位置是x的有ans[i-1],又因为相邻两数不能相等,因此要减去
【代码】
#include<bits/stdc++.h>
using namespace std;
long long n,k,x;
long long kk=1000000007;
long long f[100010],s[100010];
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)%kk;
if (x==1)
s[2]=0;
else s[2]=1;
for (int i=3;i<=n;i++)
s[i]=(f[i-1]-s[i-1]+kk)%kk;
cout<<s[n]<<endl;
return 0;
}