zoukankan      html  css  js  c++  java
  • bzoj 2669 [cqoi2012]局部极小值 DP+容斥

    2669: [cqoi2012]局部极小值

    Time Limit: 3 Sec  Memory Limit: 128 MB
    Submit: 838  Solved: 444
    [Submit][Status][Discuss]

    Description

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

    Input

    输入第一行包含两个整数nm(1<=n<=4, 1<=m<=7),即行数和列数。以下n行每行m个字符,其中“X”表示局部极小值,“.”表示非局部极小值。
     

    Output

    输出仅一行,为可能的矩阵总数除以12345678的余数。

    Sample Input

    3 2
    X.
    ..
    .X

    Sample Output

    60

    HINT

    Source

    著名大佬:看到计数类问题就要想到容斥

    数据范围十分小很容易想到状态压缩,而且我们发现,局部最小解最多只有8个。

    我们可以用f[i][sta]表示填了1-i个数,已经填完了状态为sta的方案数,然后剩下的

    随便去填,但是这样会有一个问题,就是在其它'.'的位置,如果填成了局部最小解怎么办。

    这样就会有多的方案算进去。

    所以就要用容斥的方法去解决这个问题。

    那f[i][sta]怎么算。

    格式写不出来。

    cnt的话就是暴力2*8*n*m*9 一次60000的复杂度而已,9代表判断周围。

    f[i][j]=f[i-1][j](前面填了1-i中就已经填好了j这个状态,那么剩下就在cntj-(i-1))选一个,(因为cnt包含了

    局部最小解个数),加上,所有的当前,填这一个最小解的方案数。因为填的数是不同的,所以是不同

    状态。

    复杂度是 2*8 *2*8*n*m*9差不多10000000这是极限

      1 #pragma GCC optimize(2)
      2 #pragma G++ optimize(2)
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<cstdio>
      7 #include<cstring>
      8 
      9 #define MOD 12345678
     10 using namespace std;
     11 const int dx[]={-1,-1,-1,0,0,1,1,1,0};
     12 const int dy[]={-1,0,1,-1,1,-1,0,1,0};
     13 inline int read()
     14 {
     15     int x=0,f=1;char ch=getchar();
     16     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
     17     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 
     21 int n,m,ans;
     22 char s[10][10];
     23 
     24 int Calculate()
     25 {
     26     static pair<int,int> stack[10];
     27     static int cnt[1<<8],f[30][1<<8];
     28     int i,j,k,sta,top=0;
     29     memset(cnt,0,sizeof cnt);
     30     memset(f,0,sizeof f);
     31     for(i=1;i<=n;i++)
     32         for(j=1;j<=m;j++)
     33             if(s[i][j]=='X')
     34                 stack[++top]=pair<int,int>(i,j);
     35     for(sta=0;sta<1<<top;sta++)
     36     {
     37         static bool unfilled[10][10];
     38         memset(unfilled,0,sizeof unfilled);
     39         for(i=1;i<=top;i++)
     40             if(~sta&(1<<i-1))
     41                 unfilled[stack[i].first][stack[i].second]=true;
     42         for(i=1;i<=n;i++)
     43             for(j=1;j<=m;j++)
     44             {
     45                 for(k=0;k<9;k++)
     46                     if(unfilled[i+dx[k]][j+dy[k]])
     47                         break;
     48                 if(k==9)
     49                     cnt[sta]++;
     50             }
     51     }
     52     f[0][0]=1;
     53         for(i=1;i<=n*m;i++)
     54             for(sta=0;sta<1<<top;sta++)
     55             {
     56                 (f[i][sta]+=(long long)f[i-1][sta]*max(cnt[sta]-i+1,0))%=MOD;
     57                 for(j=1;j<=top;j++)
     58                     if(sta&(1<<j-1))
     59                         (f[i][sta]+=f[i-1][sta^(1<<j-1)])%=MOD;
     60             }
     61     return f[n*m][(1<<top)-1];
     62 }
     63 void DFS(int x,int y,int cnt)
     64 {
     65     int i;
     66     if(y==m+1)
     67     {
     68         DFS(x+1,1,cnt);
     69         return ;
     70     }
     71     if(x==n+1)
     72     {
     73         (ans+=Calculate()*cnt)%=MOD;
     74         return ;
     75     }
     76     DFS(x,y+1,cnt);
     77     for(i=0;i<9;i++)
     78         if(s[x+dx[i]][y+dy[i]]=='X')
     79             break;
     80     if(i==9)
     81     {
     82         s[x][y]='X';
     83         DFS(x,y+1,-cnt);
     84         s[x][y]='.';
     85     }
     86 }
     87 int main()
     88 {
     89     int i,j,k;
     90     n=read(),m=read();
     91     for(i=1;i<=n;i++)
     92         scanf("%s",s[i]+1);
     93     for(i=1;i<=n;i++)
     94         for(j=1;j<=m;j++)
     95             if(s[i][j]=='X')
     96                 for(k=0;k<8;k++)
     97                     if(s[i+dx[k]][j+dy[k]]=='X')
     98                         return puts("0"),0;
     99     DFS(1,1,1);
    100     cout<<(ans+MOD)%MOD<<endl;
    101 }

    fi,j=fi1,jC1cntji+1+kjfi1,j{k}

  • 相关阅读:
    Android Studio查找功能(搜索功能)及快捷键
    Gson解析复杂的Bean类实现Parcelable
    Android中启动页ViewPager和ViewFlipper带指示器
    Android在listview添加checkbox实现单选多选操作问题
    Android—万能ListView适配器
    查看windosw服务器型号和序列号
    根目录/空间利用率百分百,怎么删除文件都不管用
    java.lang.OutOfMemoryError:GC overhead limit exceeded解决方
    find查找多种文件后缀
    普通用户sudo权限
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8486802.html
Copyright © 2011-2022 走看看