题目
我们有一个N位数字的电子表,当时间到达10^N-1时,下一秒就归0。下面我们给出数字0 到 9的模拟图。
对于每个数字,相邻两个+之间会有一根电子管,当显示该数字时,这些电子管就会发亮。如上图所示:数字0到9,它们的电子管数量分别是:6、2、 5、 5、 4、 5、 6、 3、 7、 5。
设现在的时刻是X, 那么可以算出该时有多少根电子管是亮的。比如:现在时刻是:99,那么共有5 + 5= 10根电子管是亮的。假如从现在时刻开始,再过Y秒后,时刻显示为Z, 我们的问题是:求最小的Y,使得时刻Z发亮的电子管数量与时刻X发亮的电子管数量相等。如:现在X = 99 ,那么再过Y = 5 秒后, 时刻变成了Z = 04, 而时刻Z发亮的电子管数量 = 6 + 4 = 10。于是Y = 5就是你要求的数。
解法
明显的数位DP。
(话说可以用贪心)
设F[i,j,0/1]表示当前枚举到第i个数,总电子管剩余j个,是否大于原数的情况下能构出的最小数。
分两种情况讨论:
①k=1 此时我们可以保证当前这个数是大于原数,所以枚举的数没有大小限制,只需要剩下的电子管够。
②k=0 目前枚举到的前i-1位和原数相等,所以枚举第i位时至少要比第i位大。
又分两种情况:
1、枚举的和第i位相等,无法保证大于。
2、比第i位大,可以保证大于。
特殊
根据题目得知,有可能数会到达顶峰时清零。
所以按照上面那样做,就可能得不出答案。
此时就再设g[i,j]表示当前枚举到第i位,剩余电子管数为j。
因为我们已经把大于原数的数都算了一遍,所以我们再算的时候就不能比原数大。
每枚举一位时,当前这一位必须大于等于枚举的数。
源码
const
b:array[0..9] of longint=(6,2,5,5,4,5,6,3,7,5);
var
a:array[1..15] of longint;
f:array[1..16,0..105,0..1] of int64;
g:array[1..16,0..105] of int64;
n,i,j,k,l,sum,i2,j2,k2:longint;
ch:char;
num,num2:int64;
function min(x,y:int64):int64;
begin
if x<y then min:=x
else
min:=y;
end;
function max(x,y:int64):int64;
begin
if x>y then max:=x
else
max:=y;
end;
begin
readln(n);
num2:=1;
for i:=1 to n do
begin
read(ch);
a[i]:=ord(ch)-48;
sum:=sum+b[a[i]];
num:=num*10+a[i];
num2:=num2*10;
end;
readln;
fillchar(f,sizeof(f),$FF);
f[1,sum,0]:=0;
for i:=1 to n do
begin
for j:=1 to sum do
begin
for l:=0 to 9 do
if j>=b[l] then
begin
for k:=0 to 1 do
if ((k=1) or (l>=a[i])) and (f[i,j,k]>=0) then
begin
if l>a[i] then
k2:=1
else
k2:=k;
j2:=j-b[l];
i2:=i+1;
if f[i2,j2,k2]=-1 then
f[i2,j2,k2]:=f[i,j,k]*10+l
else
f[i2,j2,k2]:=min(f[i2,j2,k2],f[i,j,k]*10+l);
end;
end;
end;
end;
if f[n+1,0,1]>0 then
begin
writeln(f[n+1,0,1]-num);
exit;
end;
fillchar(g,sizeof(g),$FF);
g[1,sum]:=0;
for i:=1 to n do
begin
for j:=1 to sum do
if g[i,j]>=0 then
begin
for l:=0 to a[i] do
if j>=b[l] then
begin
i2:=i+1;
j2:=j-b[l];
if g[i2,j2]=-1 then
g[i2,j2]:=g[i,j]*10+l
else
g[i2,j2]:=min(g[i2,j2],g[i,j]*10+l);
end;
end;
end;
writeln(num2-num+g[n+1,0]);
end.