• bzoj 4624 农场种植 fft


    4624: 农场种植

    Time Limit: 50 Sec  Memory Limit: 512 MB
    Submit: 48  Solved: 31
    [Submit][Status][Discuss]

    Description

    农夫约翰想要在一片巨大的土地上建造一个新的农场。 这块土地被抽象为个 R*C 的矩阵。土地中的每个方格都可
    以用来生产一种食物:谷物(G)或者是牲畜(L)。下面是一个 R 为 5,C 为 8 的土地的样例:
      12345678
    1 GLGGLGLG
    2 GGLGGLGL
    3 GGLLLGGG
    4 LLGLLGLG
    5 LGGGLGLL
    农夫约翰已经有一套设计好的他想要建造的农场的蓝图。 每一个蓝图被抽象为一个 H*W 的矩阵,其中 H≤R,W≤
    C。蓝图中的每个方格表示着农夫约翰想要生产的食物,谷物(G)或是牲畜(L)。下面是一个 H=2,W=3 的蓝图的样
    例。
      123
    1 GLL
    2 LGG
    使用这个蓝图,农夫约翰可以在土地上的某个位置建立起实际的农场。这个农场的位置可以用它的左上角的位置来
    代表, 比如这个农场被建立在土地上的(r,c)这个位置,这个农场必须整个都建立在这块土地中(也就是说 r + H
     ≤ R 并且 c + W ≤ C) 。如果在土地上的位置(r + i, c + j)的食物种类和蓝图里的位置(i + 1, j + 1)的食
    物种类相同(其中 0 ≤ i<H,0 ≤ j<W) ,那么就能出产食物。农夫约翰想要找到这样的农场位置,使得他可以
    出产最多的食物(即谷物的格数+牲畜的格数) 。如果有多于一个可能的解,输出最上方的一个,如果仍然有多于
    一个可能的解,就输出最作坊的一个。比如对于上面给出的土地和蓝图的样例,最佳的农场位置是(1, 3),这是最
    左上方的一个可行的农场,如下图所示:
      12345678
    1 GLGGLGLG
    2 GGLGGLGL
    3 GGLLLGGG
    4 LLGLLGLG
    5 LGGGLGLL
    通过在(1, 3)位置建立农场,农夫约翰可以生产出 5 格的粮食,3 格谷物和2 格牲畜,具体来说,是第一行的一
    格谷物和一个牲畜,第二行的一格牲畜和两格谷物。注意位置(2, 5)和位置(3, 2)同样能生产出 5 格谷物,但是
    农夫约翰需要的是最靠上中的最靠左的。 在除此以外的任何位置放置农场都只能生产出少于5 格的食物。
     

    Input

    输入数据中只有一组土地,第一行包含了两个整数 R 和 C,其中 0 <R,C ≤500,紧接着是 R 行每行包含 C 个字
    符来描述这片土地,接下来有一个整数 B,满足 0 <B ≤ 5,表示农夫约翰拥有的蓝图的数量,接下来是 B 个蓝
    图,每个蓝图都以包含两个整数 H 和 W 的一行开头,其中 0 <H ≤ R 并且 0 <W ≤ C,紧接着是 H 行,每行 W
     个字母来描述这个蓝图。对于每个蓝图,在一行中输出"Case #X: Y"(没有引号) ,X 是蓝图编号,从 1 开始
    ,Y 是一组用空格隔开的四个整数组成的输出,前两个整数表示最好的建造农场的位置,接下来两个整数分别表示
    可以生产的谷物和牲畜的格数。
    R,C ≤ 500,B≤5,H≤R,W≤C
     

    Output

    对于每个蓝图,在一行中输出"Case #X: Y"(没有引号) ,X 是蓝图编号,从 1 开始,Y 是一组用空格隔开的四
    个整数组成的输出,前两个整数表示最好的建造农场的位置,接下来两个整数分别表示可以生产的谷物和牲畜的格
    数。
     

    Sample Input

    5 8
    GLGGLGLG
    GGLGGLGL
    GGLLLGGG
    LLGLLGLG
    LGGGLGLL
    3 2
    3
    GLL
    LGG
    3 1
    L G G 1
    4
    GGLL

    Sample Output

    Case #1: 1 3 3 2
    Case #2: 1 2 2 1
    Case #3: 3 1 2 2

    HINT

     

    题解:

      矩阵的对应位置相乘的方法:将两个矩阵都暴力展开成一维的,第二个矩阵的空余位置补0,然后直接FFT即可。 

      先将G看成0,F看成1,再将F看成0,G看成1,做两次FFT,这样就能统计出每个位置的答案了。

         其实和一维是差不多的,只不过二维的话有点需要确定的就是,必须将小矩阵补充到大矩阵,这个很关键。

     1 #include<cstring>
     2 #include<cmath>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cstdio>
     6 
     7 #define pi acos(-1)
     8 #define N 600007
     9 using namespace std;
    10 inline int read()
    11 {
    12     int x=0,f=1;char ch=getchar();
    13     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    14     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17 
    18 int R,C,H,W,num,L;
    19 int rev[N],a[507][507],b[507][507];
    20 struct comp
    21 {
    22     double r,v;
    23     comp(){r=v=0.0;}
    24     comp(double x,double y){r=x,v=y;}
    25     void init(){r=v=0.0;}
    26     friend inline comp operator+(comp x,comp y){return comp(x.r+y.r,x.v+y.v);}
    27     friend inline comp operator-(comp x,comp y){return comp(x.r-y.r,x.v-y.v);}
    28     friend inline comp operator*(comp x,comp y){return comp(x.r*y.r-x.v*y.v,x.r*y.v+x.v*y.r);}
    29     friend inline comp operator/(comp x,int y){return comp(x.r/y,x.v/y);}
    30 }a1[N],b1[N],a2[N],b2[N],c[N];
    31 char ch[507],T[507][507];
    32 
    33 void FFT(comp *a,int flag)
    34 {
    35     for (int i=0;i<num;i++)
    36         if (i<rev[i]) swap(a[i],a[rev[i]]);
    37     for (int i=1;i<num;i<<=1)
    38     {
    39         comp wn=comp(cos(pi/i),flag*sin(pi/i));
    40         for (int j=0;j<num;j+=(i<<1))
    41         {
    42             comp w=comp(1,0);
    43             for (int k=0;k<i;k++,w=w*wn)
    44             {
    45                 comp x=a[j+k],y=w*a[j+k+i];
    46                 a[j+k]=x+y,a[j+k+i]=x-y;
    47             }
    48         }
    49     }
    50     if (flag==-1) for (int i=0;i<num;i++) a[i].r=a[i].r/num;
    51 }
    52 int main()
    53 {
    54     R=read(),C=read();
    55     for (int i=0;i<R;i++)
    56     {
    57         scanf("%s",ch);
    58         for (int j=0;j<C;j++)
    59         {
    60             if (ch[j]=='G') a1[i*C+j]=comp(1,0);
    61             else b1[i*C+j]=comp(1,0);
    62         }
    63     }
    64     for (num=1;num<=R*C*2;num<<=1,L++);if (L) L--;
    65     for (int i=0;i<num;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<L);
    66     FFT(a1,1),FFT(b1,1);
    67     int Total=read();
    68     for (int Case=1;Case<=Total;Case++)
    69     {
    70         H=read(),W=read(),memset(a,0,sizeof(a)),memset(b,0,sizeof(b));
    71         for (int i=0;i<num;i++)
    72             a2[i].init(),b2[i].init();
    73         for (int i=0;i<H;i++)
    74             scanf("%s",T[i]);
    75         for (int i=0;i<H;i++)
    76             for (int j=0;j<W;j++)
    77                 if (T[i][j]=='G') a2[R*C-1-i*C-j]=comp(1,0);
    78                 else b2[R*C-1-i*C-j]=comp(1,0);
    79         FFT(a2,1),FFT(b2,1);
    80         for (int i=0;i<num;i++)
    81             a2[i]=a1[i]*a2[i],b2[i]=b1[i]*b2[i];
    82         FFT(a2,-1),FFT(b2,-1);
    83         for (int i=0;i<R-H;i++)
    84             for (int j=0;j<C-W;j++)
    85                 a[i][j]=(int)(a2[i*C+j+R*C-1].r+0.5),
    86                 b[i][j]=(int)(b2[i*C+j+R*C-1].r+0.5);
    87         int x,y;x=y=0;
    88         for (int i=0;i<R-H;i++)
    89             for (int j=0;j<=C-W;j++)
    90                 if (a[i][j]+b[i][j]>a[x][y]+b[x][y]) x=i,y=j;
    91         printf("Case #%d: %d %d %d %d
    ",Case,x+1,y+1,a[x][y],b[x][y]);    
    92     }
    93 }
  • 相关阅读:
    学习进度条
    学习进度条
    《软件需求模式》读书笔记04
    大型网站技术架构阅读笔记5
    大型网站技术架构阅读笔记4
    大型网站技术架构阅读笔记3
    大型网站技术架构阅读笔记2
    大型网站技术架构阅读笔记1
    《uml大战需求分析》阅读笔记06
    《uml大战需求分析》阅读笔记05
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8682485.html
Copyright © 2020-2023  润新知