2024CSP-J第三题题解

题目大意

测试点包含T组数据,对于每组数据,输入一个小棒的数量n,用这n根小棒拼出一个不含前导零的整数x,输出能拼出x的最小值,每个数字的拼法如下:

解题思路

我们先给自己的思维做一下预处理,观察每个数字所需小棒的数量,列出一个数组:

sticks[10]={6,2,5,5,4,5,6,3,7,6};

不难发现,8的所用小棒最多;数字3,5,6,9这几个数字是没用的,拿3来举例,3与2这两个数字所用小棒都是5根,所以要拿5根小棒的数时,必定选择更小的2才会更优,而不是3,所以3真的真的没什么用。

还有一个可以偷鸡教你摆烂的小技巧,我们发现此题只有一个数据点,所以CCF肯定有什么规律怕被你发现,基本上可以断定这是道找规律题。

那如何找到规律呢?

方法1:电脑能干的事为什么要人做呢?

我们可以写一个程序来找规律。

#include<bits/stdc++.h>
using namespace std;
long long read(){
	long long dat=0,t=1;
	char ch;
	ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')t=-t;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		dat=(dat<<1)+(dat<<3)+(ch&15);
		ch=getchar();
	}
	return dat*t;
}
long long i,n,k,b[10];
long long ans;
long long a[10]={6,2,5,5,4,5,6,3,7,6};
void dfs(long long k,long long c[]){
	if(k<0)return;
	if(k==1){
		return;
	}
	if(k==0){
		long long num=0;
		long long flag=-1;
		for(long long j=1;j<=9;j++){//为了防止数字有前导0 
			if(c[j]>0){
				flag=j;
				num=j;
				break;
			}
		}
		if(num==0)return;
		for(long long j=0;j<=9;j++){
			long long p=c[j];
			if(flag==j)p=p-1;//有一个数字被用在了开头,故要减去 
			for(long long q=1;q<=p;q++){
				num=num*10+j;
			}
		}
		if(num<ans){
			ans=num;
		}
		return;
	}
	for(long long j=0;j<=9;j++){
		if(k>=a[j]){
			c[j]=c[j]+1;
			dfs(k-a[j],c);
			c[j]=c[j]-1;
		}
	}
	return;
}
int main(){
	for(i=1;i<=30;i++){
		if(i==1){
			cout<<-1<<endl;//所有数字所需的小棒数量都大于等于2, 1根小棒时组成不了任何数字 
			continue;
		} 
		ans=99999999;
		dfs(i,b);
		if(i==6)cout<<6<<endl;//0和6都只需要6根小棒,但0不是正整数
		else cout<<ans<<endl; 
	}
	return 0;
}

运行一下,不难发现结果为:

-1
1
7
4
2
6
8
10
18
22
20
28
68
88
108
188
200
208
288
688
888
1088
1888
2008
2088
2888
6888
8888
10888
18888

规律显而易见:1~14根小棒可以打表,而从15根开始,每7个为一组有规律,之后无脑加8。

方法2:动用聪明的大脑

我们平常在比较2个数大小时是如何比较的呢?

先比较位数,再从首位开始往后逐位比较 。

所以说,我们想要一个数较小,肯定得先使它位数最少。

而小棒总数是一定的,所以我们要多用消耗小棒数多的数字,才能使位数尽量少。

也就是说,我们需要多用数字8

所以当小棒总数多的时候,多用8可以与其他数字拉开好几位数的差距;但当小棒数量少时,其他数字组成的数可能与多个数字8组成的数拉不开差距,如0,6,9三个数字用的小棒数为6根,仅次于数字8的7根,也就是说,在每一位上,选0,6,9都只比8少一根小棒,而最少的1需要2根小棒,也就是说,至少需要能摆成2/1=2位数的小棒才能使数字8拉开差距,也就是至少2*7=14根小棒之后才有规律,所以1~14根小棒的答案得手算,从15根小棒开始就可以找规律了。

正解

找规律代码,当n小于等于14时打表,当n大于14时,若n%7==1,2,3,4,5,6,0 则对应为108,188,200,208,288,688,888,之后再加上(n+6)/7-2个8即可。

code

#include<bits/stdc++.h>
using namespace std;
long long read(){
	long long dat=0,t=1;
	char ch;
	ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')t=-t;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		dat=(dat<<1)+(dat<<3)+(ch&15);
		ch=getchar();
	}
	return dat*t;
}
long long t,n,m,i,a[8]={4444,-1,1,7,4,2,6,8};
int main(){
	t=read();
	for(;t>=1;t--){
		n=read();
		m=(n+6)/7-2;
		if(n<=7){
			printf("%lld\n",a[n]);
			continue;
		}
		if(n%7==1){
			printf("10");
		}
		if(n%7==2){
			printf("18");
		}
		if(n%7==3){
			printf("20");
		}
		if(n%7==4){
			printf("20");
		}
		if(n%7==5){
			printf("28");
		}
		if(n%7==6){
			printf("68");
		}
		if(n%7==0){
			printf("88");
		}
		for(i=1;i<=m;i++){
			printf("8");
		}
		printf("\n");
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值