5.31考试

(默认空间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
15

 

 

【数据范围】 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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值