头
这题作为 JJJ 组 第三题 起着承前启后的作用,在往年真题里难度排行靠前,需要着一些思维
题目再现

分析题目
考虑可行性
我们思考是否存在数字无法被表示,容易发现
一位数字时需要的木棍数分别为 6,2,5,5,4,5,6,3,7,6{6,2,5,5,4,5,6,3,7,6}6,2,5,5,4,5,6,3,7,6
显然如果木棍数为 111 无法组成
显然两位可重复数字可以组成的数字有 4,144,144,14 (其中每个整数皆可到达)
显然我们可以在每两位数字后补一个数字 ,木棍数到达范围 6,216,216,21
从而易得,其后的每个数字都可以用木柴拼得
考虑最小
我们发现,当取尽可能多 111 时可以使组成数字尽可能大,取尽可能多 888 可以使组成数字尽可能小,根据上面的可行性证明, nnn 位数字可以取得 2n,7n2n,7n2n,7n ,由此我们可以求得当前木棍数可以得到的最小数字位数 len=⌊(s+6)/7⌋len=\lfloor (s+6)/7 \rfloorlen=⌊(s+6)/7⌋ 。
考虑填数字
容易想到的,我们要保证每一位数字取完后,剩下的木棍数还满足 (s′+6)/7<=len−1(s'+6)/7 <=len-1(s′+6)/7<=len−1 (len为当前确认的最小位数)。
从这条思路出发,我们从头开始,对每一位数字从 0~9 进行枚举 ,满足上式,则取之,就可以得到最优解。
考虑下界
我们发现,此时还有 s′>=(len−1)∗2s'>=(len-1)*2s′>=(len−1)∗2 的约束,但是由于我们尽可能往最短的位数靠近,且一定满足上界的判定(开头已经取了最大)。由此,我们只要考虑最后一位数字的合法性即可。
参考代码
cpp
//枚举 查看大致逻辑
//发现位数技巧 构造
#include<bits/stdc++.h>
using namespace std;
int n;
int f[10]={6,2,5,5,4,5,6,3,7,6};
int g[8]={0,-1,1,7,4,2,6,8};
string s;
int main()
{
int T;
cin>>T;
while(T--)
{
s="";
cin>>n;
int len=(n+6)/7;
if(n<=7)
{
cout<<g[n]<<endl;
continue;
}
for(int i=1;i<=len;i++)
{
int j=(i==1?1:0);
for(;j<=9;j++)
{
int now=n-f[j];
if((now+6)/7+i>len||now<0)
continue;
s+=(j+'0');
n-=f[j];
break;
}
}
cout<<s<<endl;
}
}
巧姐
从贪心的角度去看,我们想要取尽可能多的 888 ,满足位数最少。我们发现,当取得一位 888 时,剩下的数字必然是 888 (由公式中除法可知),所以我们的组合后面一定是一串 888 (如果有的话)。
所以我们可以对木柴数进行枚举,根据对 777 的余数进行分类讨论。
此处不多赘述,上图,可以参考洛谷题解前几篇

结尾
这题提供了多种解法,是除了 dp 之外开发思路的好的方向,考场上可以很好区分层次。
完结撒花