【利用同余的DP】符文之语(chars. pas/c/cpp)

  符文之语(chars. pas/c/cpp)

  【题目描述】

当小FF来到神庙时,神庙已经破败不堪了。但神庙的中央有一个光亮如新的石台。小FF走近石台,发现石台上有一个数串,而数串的上方刻着一串古老的符文之语。精通古符文之语的小FF不费吹灰之力就读懂了文章的意思,其大意是:对于石台上的一串数字,你可以在适当的位置加入乘号(设加了k个,当然也可不加,即分成k+1个部分),设这k+1个部分的乘积(如果k=0,则乘积即为原数串的值)对m的余数(即mod m)为x;现求x能达到的最小值及该情况下k的最小值,以及x能达到的最大值及该情况下的k的最小值(可以存在x的最小值与最大值相同的情况)。小FF还知道,如果他找到了正确的答案,那么就可以通往神庙的下层了。但这个问题似乎不太好解决,小FF就找到了你,并答应找到财宝以后和你二八分(当然你拿二……)。

【输入格式】

第一行为数串,且数串中不存在0;

第二行为m。

【输出格式】

四个数,分别为x的最小值和该情况下的k,以及x的最大值和该情况下的k,相邻两个数之间用一个空格隔开。

【输入样例】

    4421

    22

【输出样例】

    0 1 21 0

【数据范围】

对于30%的数据:2≤字符串长度L≤50。

对于100%的数据:2≤字符串长度L≤1000;2≤m≤50。

=====================================

==========================

var
  st:ansistring;
  m,st_l:longint;
  f:Array[0..1000,0..50]of longint;
  dist:array[0..1000,0..1000]of longint;
  a:array[1..1000]of longint;
procedure init;
begin
  assign(input,'chars.in');
  assign(output,'chars.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

procedure main;
var
  i,j,k:longint;
begin
  readln(st);
  st_l:=length(st);
  
  readln(m);
  fillchar(f,sizeof(f),$ff);
  dist[1,0]:=0;
  for i:=1 to st_l do
    for j:=i to st_l do
      begin
        dist[i,j]:=(dist[i,j-1]*10+ord(st[j])-48)mod m;
      end;
  f[0,1]:=0;
  for i:=1 to st_l do
    for j:=i-1 downto 0 do
      for k:=0 to m do
        if f[j,k]<>-1 then
          begin
            if f[i,(k*dist[j+1,i])mod m]=-1 then f[i,(k*dist[j+1,i])mod m]:=f[j,k]+1
             else if f[i,(k*dist[j+1,i])mod m]>f[j,k]+1 then f[i,(k*dist[j+1,i])mod m]:=f[j,k]+1;
          end;
  for i:=0 to m do
    if f[st_l,i]<>-1 then
      begin
        write(i,' ',f[st_l,i]-1,' ');
        //减1的原因是开始按只有一段的时候按的是1来算得..
        break;
      end;
  for i:=m-1 downto 0 do
    if f[st_l,i]<>-1 then
      begin
        write(i,' ',f[st_l,i]-1);
        break;
      end;
end;

begin
  init;
  main;
  terminate;
end.


 

你可能感兴趣的:(NOIP2011黎明前夕的黑暗,动态规划)