(默认空间512MB,时间2s)
T1 Classroom Watch:
【问题描述】
给出一个正整数 n,现在问存在多少个 x,使得 x在十进制下的每一位之和加上 x 等于 n。
【输入】
共 1 行,一个正整数n 。
【输出】
第一行输出一个整数 m,表示有 m 个符合条件的 (若没有符合条件的 ,请只输出一个 0)。
下面m行,每行一个 x ,x按从小到大输出。
【输入输出样例1】
num.in | num.out |
21 | |
【数据范围】 1<=n<=10^9
最开始想到的肯定是从1枚举到n,然后一个一个累加,判断;但是10^9显然是不可能的。
所以不能从1开始枚举,不然大数据就过不了了。
如果是大数据,数字一定要满足一定大小,我们可以从每个位数的累加和出发,n最大为10^9,而所有位数加起来最大是999999999 九个九,所以只要从n-81枚举到n就好了。
代码:
#include<bits/stdc++.h>
long long n,ans=0,t,I,f[10000000];
using namespace std;
inline void work()
{
scanf("%lld",&n);
for(int i=n-81;i<=n;i++)
{
t=0;
I=i;
while(I)
{
t+=I%10;
I/=10;
}
t+=i;
if(t==n)
{
ans++;
f[ans]=i;
}
}
printf("%lld\n",ans);
for(int i=0;++i<=ans;i) if(f[i]>0)printf("%lld\n",f[i]);
}
int main()
{
work();
return 0;
}
T2组合技能(combo):
题目描述
蓝月商城出新技能书了!!
如果古天乐想购买“旋风斩”,则他需要花费A元;如果古天乐想买“半月弯刀”,则需要B元;如果古天乐两个一起买,则需要C元。
蓝月的设计师非常有头脑,每样商品的利润都是相同的。即假设旋风斩和半月弯刀的成本为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
Sample Input 0
3
275 214 420
6 9 11
199 199 255
Sample Output 0
69
4
143
(我是古天乐,是兄弟就来砍我)。这题是真的水,直接从式子着手:A-a=B-b=C-a-b,同事加a和b,变成:A+b=B+a=C
那么a=C-B; ans=A-a;
整理一下ans=A-a=A-(C-B)=A-C+B;
程序:
#include<bits/stdc++.h>
long long A,B,C,a,b,t,ans;
using namespace std;
int main()
{
scanf("%lld",&t);
for(int i=0;++i<=t;i)
{
scanf("%lld%lld%lld",&A,&B,&C);
b=C-A;
ans=B-b;
printf("%lld\n",ans);
}
return 0;
}
T3 surface :
古天乐在搭积木,积木图可以抽象为一个n*m的网格图,其中第(i,j)的位置有A[i][j]个积木。求表面积。
格式
输入第一行两个数n,m,接下来n行每行m个数,表示A[i][j]。
输出一个数,表示表面积。
范围
Sample Input 0
1 1
1
Sample Output 0
6
Sample Input 1
3 3
1 3 4
2 2 3
1 2 4
Sample Output 1
60
我是先把ans赋值为2*n*m,就是上面和下面的面积,在读入接下来的a[][]矩形是,如果遇到0,那么久ans-=2;因为就没有上下表面积了,,然后分了三种情况,四个角的(四个if判断四个角):
(i==1&&j==1)||(i==1&&j==m)||(i==n&&j==1)||(i==n&&j==m)
然后是除了角的边(为了不让角重复判断,就开了A[][]数组来记录a[][]这个位置有没有计算过):
只要两个if:
if((i==1||i==n)&&A[i][j]==0)
if((j==1||j==m)&&A[i][j]==0)
然后就计算其他的就好了。
程序:
#include<bits/stdc++.h>
int n,m,a[111][111];
long long ans=0,front,behind,Left,Right;
bool A[111][111];
using namespace std;
int main()
{
scanf("%d%d",&n,&m);
memset(A,0,sizeof(A));
ans=2*n*m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==0) ans-=2,A[i][j]=1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]!=0)
{
// (i==1&&j==1)||(i==1&&j==m)||(i==n&&j==1)||(i==n&&j==m)
if(i==1&&j==1&&A[i][j]==0)
{
Right=a[i][j]-a[i][j+1];
if(Right<0) Right=0;
behind=a[i][j]-a[i+1][j];
if(behind<0) behind=0;
ans+=a[i][j]*2+Right+behind;
A[i][j]=1;
}
if(i==1&&j==m&&A[i][j]==0)
{
Left=a[i][j]-a[i][j-1];
if(Left<0) Left=0;
behind=a[i][j]-a[i+1][j];
if(behind<0) behind=0;
ans+=a[i][j]*2+Left+behind;
A[i][j]=1;
}
if(i==n&&j==1&&A[i][j]==0)
{
front=a[i][j]-a[i-1][j];
if(front<0) front=0;
Right=a[i][j]-a[i][j+1];
if(Right<0) Right=0;
ans+=a[i][j]*2+front+Right;
A[i][j]=1;
}
if(i==n&&j==m&&A[i][j]==0)
{
Left=a[i][j]-a[i][j-1];
if(Left<0) Left=0;
front=a[i][j]-a[i-1][j];
if(front<0) front=0;
ans+=a[i][j]*2+Left+front;
A[i][j]=1;
}
if((i==1||i==n)&&A[i][j]==0)
{
Left=a[i][j]-a[i][j-1];
if(Left<0) Left=0;
Right=a[i][j]-a[i][j+1];
if(Right<0) Right=0;
ans+=a[i][j]+Left+Right;
A[i][j]=1;
if(i==1)
{
behind=a[i][j]-a[i+1][j];
if(behind<0) behind=0;
ans+=behind;
}
else
{
front=a[i][j]-a[i-1][j];
if(front<0) front=0;
ans+=front;
}
}
if((j==1||j==m)&&A[i][j]==0)
{
front=a[i][j]-a[i-1][j];
if(front<0) front=0;
behind=a[i][j]-a[i+1][j];
if(behind<0) behind=0;
ans+=a[i][j]+behind+front;
A[i][j]=1;
if(j==1)
{
Right=a[i][j]-a[i][j+1];
if(Right<0) Right=0;
ans+=Right;
}
else
{
Left=a[i][j]-a[i][j-1];
if(Left<0) Left=0;
ans+=Left;
}
}
if(A[i][j]==0)
{
front=a[i][j]-a[i-1][j];
if(front<0) front=0;
behind=a[i][j]-a[i+1][j];
if(behind<0) behind=0;
Left=a[i][j]-a[i][j-1];
if(Left<0) Left=0;
Right=a[i][j]-a[i][j+1];
if(Right<0) Right=0;
ans+=Left+Right+front+behind;
A[i][j]=1;
}
}
}
}
cout<<ans;
return 0;
}
T4:红皇后的旅行(redqueen.cpp)
题目描述
给定一个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。
输出第一行一个数,最小步数,第二行输出方案。
范围
Sample Input 0
7
6 6 0 1
Sample Output 0
4
UL UL UL L
Sample Input 1
6
5 1 0 5
Sample Output 1
Impossible
Sample Input 2
7
0 3 4 3
Sample Output 2
2
LR LL
这就是一道裸的BFS,然而我考试的时候写DFS,还写炸了。。。
程序:
#include<bits/stdc++.h>
using namespace std;
int dx[8]={0,-2,-2,0,2,2,0},dy[8]={0,-1,1,2,1,-1,-2};
string Do[8]={"","UL","UR","R","LR","LL","L"};
int n,t,h=1,p[201][201];
struct E
{
int x,y,z;
}q[100020],s,e;
struct EE
{
int x,y,z;
}f[201][201];
inline void work(int x,int y)
{
if(f[x][y].x==s.x&&f[x][y].y==s.y)
cout<<Do[f[x][y].z]<<' ';
else
{
work(f[x][y].x,f[x][y].y);
cout<<Do[f[x][y].z]<<' ';
}
}
int main()
{
scanf("%d%d%d%d%d",&n,&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||y1<0||y1>=n) 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)
{
cout<<z+1<<endl;
work(x1,y1);
return 0;
}
}
}
}
cout<<"Impossible";
return 0;
}
T5:构造序列(construct.cpp)
题目描述
有一个长度为n的序列A,其中A[1]=1,A[n]=x,A[2…n-1]可以是1至k间任意一个正整数。求有多少个不同的序列,使得相邻两个数不同。
答案对10^9+7取模。
格式
输入共一行,包含三个数,n,k,x。
输出一个数,表示答案。
范围
Sample Input 1
4 3 2
Sample Output 1
3
考试的时候,就一直想着是排列组合,一维能用O(1)写出来,当然我肯定没有推出来。
知道考完我才(从别人那里)知道这题原来是递推!
•先考虑如果没有A[1]和A[n]的限制,怎么办?
•答案就是k*(k-1)^(n-1)
•如果只有A[1]的限制?
•答案就是(k-1)^(n-1)
这是最基本的排列组合。
我们可以先写一个暴力DP:
•F[i][j]表示前i个格子已经涂好颜色了,第i格的颜色是j的方案数
•枚举第i+1格的颜色k,如果j!=k,则F[i+1][k]+=F[i][j]
然后随便试一组数据(不要像样例那么简单的),就可以找到规律了。
q=m; p=y;
m=(p*(k-1))%1000000007;
y=(p*(k-2)%1000000007+q)%1000000007;
算了还是直接看程序把。。。
程序:
#include<bits/stdc++.h>
long long n,k,x,y,p,q,m;
using namespace std;
int main()
{
scanf("%lld%lld%lld",&n,&k,&x);
m=1; y=0;
for(int i=2;i<=n;i++)
{
q=m; p=y;
m=(p*(k-1))%1000000007;
y=(p*(k-2)%1000000007+q)%1000000007;
}
if(x==1) cout<<m;
else cout<<y;
return 0;
}