{题解}[jzoj1299] 洗盘子(cleanup.pas/cpp)

jzoj1299

Description

  有N(1<=N<=40000)个奶牛到FJ的餐厅吃饭,餐厅里有M(1<=M<=N)种菜,每头牛有自己喜欢的菜的编号P_i(1<=P_i<=M),每头牛只吃自己喜欢的这道菜。
  牛儿们在外面排着队进来,按照排队顺序一批一批进来,每批可以同时进来任意头牛,每一批吃完(注意包括最后一批)都要进行打扫,如果这批牛中一共需要K种菜,那么吃完后的打扫时间为K*K。
  请你帮助FJ如何安排各批次使得总打扫时间最少。

给你一个序列,要求用任意个区间覆盖它,定义区间的值为该区间中 不同数字个数 2
求最小区间和

Idea

考虑使用DP解决
设f[i]为1~i打扫总时间
kind(x,y)xy
f[i]=f[ij]+kind(ij,i)2

对于50%的数据

暴力计算 kind(x,y)

对于80%的数据

在上文基础上,
kind(x,y)kind(x1,y)
并且加入剪枝
j
j2>f[i]jf[i]
但是还是会TLE

对于100%的数据

那么我们考虑空间换时间思想
典型的,我们尝试前缀和优化
我们把程序上下左右看了一遍,和前缀和有个Egg关系啊!
不过,多番思(Read)虑(TJ)后,终于有了思路
我们定义 p[i,k]ki
于是就有 fi:=min(fpi,k1+k2)[0<k<n]
于是,我们考虑转移 pi,k
x
[lastx<pj]pi,j:=pi1,j1;
[lastx>pj]pi,j:=pi1,j;
lastxx

Code

对于80%

const
        maxn=40000;
        maxm=40000;
var
        n,m:longint;
        i,j,l,k:longint;
        f:array[0..maxn] of longint;
        p:array[0..maxn] of longint;
        bz:array[0..maxm] of boolean;
function min(a,b:longint):longint;
begin
        if a<b then exit(a) else exit(b);
end;
begin
        assign(input,'cleanup.in');reset(input);assign(output,'cleanup.out');rewrite(output);
        readln(n,m);
        for i:=1 to n do
        begin
                readln(p[i]);
                f[i]:=i;
        end;

        for i:=2 to n do
        begin
                k:=0;
                for j:=0 to i-1 do
                begin
                        f[i]:=min(f[i],f[i-j]+k*k);
                        if not bz[p[i-j]] then
                        begin
                                inc(k);
                                bz[p[i-j]]:=true;
                        end;
                        if k*k>f[i] then break;
                end;
                for l:=j downto 0 do bz[p[i-l]]:=false;
        end;

        writeln(f[n]);
        close(input);close(output);
end.

对于100%

const
        maxn=40000;
        maxm=40000;
var
        n,m:longint;
        maxlen:longint;
        i,j,l,k:longint;
        p,f:array[-1..maxn] of longint;
        last:array[0..maxm] of longint;
function min(a,b:longint):longint;
begin
        if(a<b)then exit(a) else exit(b);
end;
procedure init;
var
        i:longint;
begin
        readln(n,m);
        maxlen:=trunc(sqrt(n))+1;
end;
procedure work;
var
        x:longint;
        i,j:longint;
begin
        f[-1]:=100000000;
        readln(x);
        last[x]:=1;
        f[1]:=1;p[1]:=1;
        fillchar(last,sizeof(last),255);
        for i:=2 to n do
        begin
                readln(x);
                p[0]:=i;
                for j:=maxlen downto 1 do
                        if last[x]<p[j] then p[j]:=p[j-1];

                f[i]:=i;
                for j:=1 to maxlen do
                        f[i]:=min(f[i],f[p[j]-1]+j*j);

                last[x]:=i;
        end;
end;
procedure print;
begin
        writeln(f[n]);
end;
begin
        assign(input,'cleanup.in');reset(input);assign(output,'cleanup.out');rewrite(output);
        init;
        work;
        print;
        close(input);close(output);
end.

你可能感兴趣的:({题解}[jzoj1299] 洗盘子(cleanup.pas/cpp))