BZOJ 2669 局部极小值 CQOI2012

来源:互联网 发布:什么是返利网和淘宝客 编辑:程序博客网 时间:2024/05/16 01:52

局部最小值

题目网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2669

题目描述

有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。
给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

数据范围

1<=n<=4, 1<=m<=7

题解

这一题,挺难的,经过了我几个小时的努力,我还是对了,O(∩_∩)O~~
动态规划,F[i][s]表示前i个数已经填完了,位置为X的点的填充情况为s时(s为2进制),填数的方案有多少。预处理出Rest数组,Rests(s为2进制)表示位置为X的点的填充情况为s时,有多少个位置可以放数(包括位置为X的点)。
状态转移方程显然为:
这里写图片描述
其中-i+1等于-(i-1)。

但是我们发现这样做会把不是局部最小值的位置也会当成局部最小值,于是我们算出所有把别的位置也当成X的情况(不重复),对于每种情况跑一边动态规划。如果多选偶数个X,则加到答案贡献上,如果是奇数个,则对答案的贡献为负数。

Code(Pascal)

//唉,好像那一题我排名第三哦label 123;CONST    mo=12345678;var    wz:array[1..8,1..2] of longint=    ((-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1));    n,m,j,k,l,t,y,i,o,p,kww:longint;    ch:array[0..5,0..8] of char;    jk,rr:array[0..5,0..8] of longint;    kx:array[0..30,1..2] of longint;    bz:array[0..30] of boolean;    m2:array[0..10] of longint;    f:array[0..28,0..512] of int64;    rest:array[0..512] of int64;    lz:array[0..30] of longint;    ans:int64;function ok(a,b:longint):boolean;    begin        if (a>0) and (a<=n) and (b>0) and (b<=m) then exit(true)        else exit(false);    end;function js:int64;     var         i,j,l,s,p:longint;     begin         for i:=0 to m2[k]*2-1 do         begin             rest[i]:=0;             inc(kww);             for j:=1 to k do             if m2[j] and i=0 then             begin                 rr[kx[j,1],kx[j,2]]:=kww;                 for l:=1 to 8 do                 rr[kx[j,1]+wz[l,1],kx[j,2]+wz[l,2]]:=kww;             end;             for j:=1 to n do             for l:=1 to m do             if rr[j,l]<>kww then inc(rest[i]);         end;         if k=0 then         begin             js:=1;             for l:=1 to n*m do             js:=(js*l) mod mo;             exit;         end;         for i:=1 to n*m do         for s:=0 to m2[k]*2-1 do         f[i,s]:=0;         f[0,0]:=1;         for i:=1 to n*m do         for s:=0 to m2[k]*2-1 do         if rest[s]-i+1>0 then         begin             f[i,s]:=f[i-1,s]*(rest[s]-i+1) mod mo;             for l:=1 to k do             if s and m2[l]>0 then             f[i,s]:=(f[i,s]+f[i-1,s-m2[l]]) mod mo;         end;         js:=f[n*m,m2[k]*2-1];     end;procedure dg(o,kk,uu:longint);    var        i,j,l,pp,ss:longint;    begin        ans:=(ans+o*js+mo) mod mo;        ss:=kk*m+uu;        for i:=kk to n do        for l:=1 to m do        if i*m+l>=ss then        if ch[i,l]='.' then        begin            pp:=0;            for j:=1 to 8 do            if ch[i+wz[j,1],l+wz[j,2]]='X' then            begin                inc(pp);                break;            end;            if pp=0 then            begin                inc(k);                kx[k,1]:=i;                kx[k,2]:=l;                ch[i,l]:='X';                dg(0-o,i,l+1);                dec(k);                ch[i,l]:='.';            end;        end;    end;begin    m2[1]:=1;    for i:=2 to 10 do    m2[i]:=m2[i-1]*2;    k:=0;    readln(n,m);    for i:=1 to n do    begin        for l:=1 to m do        begin            read(ch[i,l]);                if ch[i,l]='X' then                begin                    inc(k);                    kx[k,1]:=i;                    kx[k,2]:=l;                end;            end;            readln;        end;        for i:=1 to n do        for l:=1 to m do        if ch[i,l]='X' then        for j:=1 to 8 do        if (ch[i+wz[j,1],l+wz[j,2]]='X') and ok(i+wz[j,1],l+wz[j,2]) then        begin            ans:=0;            goto 123;        end;        ans:=0;        if k<>0 then        dg(1,1,1);        123:writeln(ans);end.
4 0
原创粉丝点击