4和7
由题目m的数据范围可以知道,(m<=1000000000)单纯的转移是不可以的:f[i]:=max(f[i-1],f[i-7])+a[i];
- a[i]的数组开不下;
- 循环1到1000000000也不太可行
解决:离散化
A[i]数组表示每个点的药品价值;b[i]数组表示每个点的位置,进一步观察n的范围(n<=100000),点的数目可以利用。那么前一个点与后一个点有什么关系?
当b[i]-b[i-1]>18时,将b[i]的坐标更新为b[i-1]+18,这样每两个点之间最大距离为18,位置范围缩小到了18*100000。
证明:为什么当两个点之间距离>18时距离可以缩小到18,因为大于等于18的数都可以由4和7拼出来,即两个点之间一定能转移。由裴蜀定理ax+by=m,当m为gcd(a,b)的倍数时方程一定有解,但这个题要求x>=0,y>=0,可得到当m>=18时一定有非负整数解。
F[i]:=max(f[i-4],f[i-7])+c[i]; c[i]就是按照以上方式处理得到的新数列,当两点之间距离>18时就把距离缩到18,当两个点重合时,c[i]为两个点a[i]的累加值。最需注意的一点是:在<=18的范围内,1,2,3,5,6,9,10,13,15,17的c值应为0,因为无法由它转移,所以c值设为0,防止f的转移。
代码实现:
program exam;
uses math;
var
i,j:longint;
n,m,p,ans:int64;
f:array[-10..2000000] of int64;
a:array[1..2000000] of int64;
c:array[1..2000000] of int64;
b:array[1..2000000] of int64;
procedure qsort(l,r:int64);
var
x,i,j,y:int64;
begin
i:=l;
j:=r;
x:=b[(i+j) div 2];
repeat
while b[i]<x do
inc(i);
while b[j]>x do
dec(j);
if i<=j then
begin
y:=b[i];
b[i]:=b[j];
b[j]:=y;
y:=a[i];
a[i]:=a[j];
a[j]:=y;
inc(i);
dec(j);
end;
until i>j;
if (i<r) then
qsort(i,r);
if (l<j) then
qsort(l,j);
end;
procedure chuli;
var
i,j:longint;
t,k:int64;
begin
t:=0;
p:=b[1]; // 记录一个新数组上一个点位置
c[p]:=a[1];
for i:=2 to n do
begin
if b[i]=b[i-1] then
c[p]:=c[p]+a[i];
if b[i]<>b[i-1] then
begin
if b[i]-b[i-1]>18 then
begin
c[p+18]:=a[i];
p:=p+18;
end;
if b[i]-b[i-1]<=18 then
begin
k:=b[i]-b[i-1];
c[p+k]:=a[i];
p:=p+k;
end;
end;
end;
end;
begin
assign(input,'hop10.in');
reset(input);
readln(n,m);
for i:=1 to n do
readln(a[i],b[i]);
qsort(1,n);
chuli;
c[1]:=0;
c[2]:=0;
c[3]:=0;
c[5]:=0;
c[6]:=0;
c[9]:=0;
c[10]:=0;
c[13]:=0;
c[17]:=0;
for i:=1 to p do
f[i]:=max(f[i-4],f[i-7])+c[i];
for i:=1 to p do
if ans<f[i] then
ans:=f[i];
writeln(ans);
close(input);
end.