【NOIP复赛模拟题(一)】【第2题…

【NOIP复赛模拟题(一)】【第2题】破译密码

Time Limit:1000MS  Memory Limit:32768K
Total Submit:9 Accepted:5

Description

破译密码(password.pas/c/cpp)

【题目描述】
  Feli得到总部发来的消息,我军特种部队已经截获敌人的一个密码本,但是这个密码本本身是由密码写成的。为了给敌人造成沉重的打击,Feli必须尽快破译密码。
  经过一天一夜的探索,Feli发现日军密码本实际上记载着一个数列,而最终密码由这个数列经过某种运算得到。运算是这样的:
  1.把数列从小到大排序。
  2.(分拆)在排好序的数列中,任选一个数,这个数将把原数列分成左右两个数列(选出的数不在新数列中,并且新数列有可能为空)。
  3.对每个新数列进行第2步操作,直到最后得到的数列长度都为1,即全部变成单个数。
  4.将第3步得到的每个数*(得到它所需的分拆次数+1),累加得到一个和。
  5.重复2,3,4操作,直到遍历所有的分拆可能,这时,所得的和当中最小的一个就是日军的最终密码。
  6.现在Feli请求你帮助,尽快破译这段密码!

Input

  输入文件password.in第一行为N,N≤1000,表示密码本记录的数列的长度。
  下一行共有N个数,即日军密码本记载的数列。

Output

  输出文件password.out为一个整数,即日军最终密码。

Sample Input

3
1 3 2

Sample Output

10

Hint

【样例说明】
  
  1.数列排序得 1 2 3
  2.选出一个数 2
  3.分拆得
      2
     / \
     1 3
   此时新的数列(1,3)长度都已经是1,因此无须再分拆
  4.求和,2*1+1*2+3*2=10(2在原数列,故乘1;1和3都经过一次分拆,故乘2)
  2.选出一个数 1
  3.分拆得
      1
      \
      2 3
   2 3中选一个数 2,分拆得
     1
      \
       2
       \
        3
   4.求和,1*1+2*2+3*3=14
    ……
    ……
  所有和当中最小的是10,故输出10

Source

 

 

开始还以为是树形动归,所以就直接搜了。

其实就是个区间动归。其中要用到“四边形不等式”。

具体我也不懂。。

 

 

var
 n:longint;
 a:array[0..1000+1]of longint;
 f,q,w:array[0..1000+1,0..1000+1]of longint;

procedure init;
var
 i,j:longint;
begin
 read(n);
 for i:=1 to n do read(a[i]);
 for i:=1 to n-1 do
  for j:=i+1 to n do
   if a[i]>a[j] then begin a[0]:=a[i]; a[i]:=a[j]; a[j]:=a[0]; end;
end;
procedure main;
var
 i,j,k,l,minl,min:longint;
begin
 for i:=1 to n do w[i,i]:=a[i];
 for i:=1 to n-1 do
  for j:=i+1 to n do
   w[i,j]:=w[i,j-1]+a[j];


 for i:=1 to n do f[i,i]:=a[i];
 for i:=1 to n do q[i,i]:=i;

 for k:=2 to n do
  for i:=1 to n-k+1 do
   begin
   j:=i+k-1;
   min:=maxlongint;
   for l:=q[i,j-1] to q[i+1,j] do
    if f[i,l-1]+f[l+1,j]
     begin
     min:=f[i,l-1]+f[l+1,j];
     minl:=l;
     end;
   f[i,j]:=min+w[i,j];
   q[i,j]:=minl;
   end;
 write(f[1,n]);
end;

begin
 assign(input,'password.in');
 assign(output,'password.out');
 reset(input);
 rewrite(output);
 init;
 main;
 close(input);
 close(output);
end.

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值