4和7

4和7

由题目m的数据范围可以知道,(m<=1000000000)单纯的转移是不可以的:f[i]:=max(f[i-1],f[i-7])+a[i];

  1. a[i]的数组开不下;
  2. 循环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.

原文地址:https://www.cnblogs.com/fengxiudong/p/6017312.html