【noip模拟】局部最小值

TimeLimit: 1000ms               MemoryLimit: 256MB

Description

有一个n行m列的整数矩阵,其中1到n×m之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。

给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

Input

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

Output

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

Sample Input

【样例输入1】
2 4
.X..
...X
【样例输入2】
4 2
X.
..
..
X.
【样例输入3】
1 2
XX

Sample Output

【样例输出1】
2100
【样例输出2】
2520
【样例输出3】
0

HINT

对于10%的数据,$n≤3,m≤3$

对于20%的数据,$n≤3,m≤4$

对于45%的数据,$n≤4,m≤4$

对于60%的数据,$n≤4,m≤5$

对于80%的数据,$n≤4,m≤6$

对于100%的数据,$n≤4,m≤7$

[吐槽]

  这题的话。。在模拟题里面出现了。。两遍啊哈哈。。

  第一次做的时候啃得挺。。辛苦。。不过不得不说这个状压还是很好玩的

[题解]

  首先看看这个局部最小值有什么可以利用的地方。。

  画一下图就会发现好像最多只有8个

  这个数字很小所以就可以。。。

  考虑状压

  考虑用$f_{i,j}$表示填完了$1$到$i$这$i$个数,局部最小值的填充情况为$j$的方案数

  用$cnt_i$表示局部最小值的填充情况为$i$时,还有多少个位置是可以填数的

  那么就可以得到:

  $f_{i,j} = f_{i-1,j}*(cnt_j - (i -1)) + \sum\limits_{k\in j} f_{i-j,k}$

  为啥是$cnt_j - (i - 1) $呢

  因为本来有$cnt_j$个位置可以填,但是现在已经有$i - 1$个位置已经确定下来了,并不能填所以要减掉

  考虑cnt怎么算

  首先我们枚举一下状态$ i (0 <= i <= (1<<tot) -1 )$ (tot为X的个数)

  因为现在已经填充的局部最小值有哪些是确定了的,那就意味着状态中非填充的局部最小值是不能填的

  然后因为我们接下来填的数是剩下的数中最小的,所以这个数肯定不能填在局部最小值的相邻位置

  那么就很显然是枚举一下$i$中没有填充的局部最小值,然后把这些地方减掉就好啦

  然后就是$k$怎么枚举

  我们可以每次取lowbit,统计完之后就把最后一位去掉(实现起来就是$k$ & $(k - 1) $)就ok了

  最后还有一个小小的问题

  题目要求只能有这些标为X的地方是局部最小值,其他的地方不能是

  而我们的这种奇妙填数方法可能会导致有别的格子不小心变成了局部最小值了,这是不合法的

  所以就应该要把这些方案减掉

  具体实现其实很简单粗暴,直接枚举有哪些位置可能变成局部最小值

  用同样的方法求出方案数,然后减掉就好(其实就是一个dfs巨无敌粗暴)

  

  然后就很愉快滴搞完啦ovo

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #define MOD 998244353
  5 #define ll long long
  6 using namespace std;
  7 const int dx[9]={0,-1,0,1,0,-1,-1,1,1};
  8 const int dy[9]={0,0,1,0,-1,-1,1,-1,1};
  9 struct xxx
 10 {
 11     int x,y;
 12 }X[110];
 13 char a[10][10];
 14 ll b[10][10],cnt[1<<9],f[110][1<<9];
 15 int n,m,tot;
 16 ll ans;
 17 int dfs(int x,int y,int op);
 18 ll calc();
 19 bool ok(int x,int y);
 20 bool check();
 21
 22 int main()
 23 {
 24     scanf("%d%d\n",&n,&m);
 25     for (int i=1;i<=n;++i)
 26     {
 27         for (int j=1;j<=m;++j)
 28             scanf("%c",&a[i][j]);
 29         scanf("\n");
 30     }
 31     if (!check()) {printf("0\n");return 0;}
 32     ans=0;
 33     dfs(1,1,0);
 34     printf("%lld\n",ans);
 35 }
 36
 37 int dfs(int x,int y,int op)
 38 {
 39     int mark=op?-1:1;
 40     if (x==n+1)
 41     {ans=(ans+MOD+mark*calc())%MOD;return 0;}
 42     if (a[x][y]==‘.‘)
 43     {
 44         a[x][y]=‘X‘;
 45         if (check())
 46         {
 47             if (y==m) dfs(x+1,1,op^1);
 48             else dfs(x,y+1,op^1);
 49         }
 50         a[x][y]=‘.‘;
 51     }
 52     if (y==m) dfs(x+1,1,op);
 53     else dfs(x,y+1,op);
 54 }
 55
 56 ll calc()
 57 {
 58     tot=0;
 59     for (int i=1;i<=n;++i)
 60         for (int j=1;j<=m;++j)
 61             if (a[i][j]==‘X‘)
 62                 X[++tot].x=i,X[tot].y=j;
 63     int x,y;
 64     memset(cnt,0,sizeof(cnt));
 65     for (int i=0;i<1<<tot;++i)
 66     {
 67         for (int j=1;j<=n;++j)
 68             for (int k=1;k<=m;++k)
 69                 b[j][k]=1;
 70         for (int j=0;j<tot;++j)
 71         {
 72             if (1<<j&i) continue;
 73             x=X[j+1].x,y=X[j+1].y;
 74             b[x][y]=0;
 75             for (int k=1;k<=8;++k)
 76                 if (ok(x+dx[k],y+dy[k]))
 77                     b[x+dx[k]][y+dy[k]]=0;
 78         }
 79         for (int j=1;j<=n;++j)
 80             for (int k=1;k<=m;++k)
 81                 cnt[i]=(cnt[i]+b[j][k])%MOD;
 82     }
 83     //for (int i=0;i<1<<tot;++i) printf("%d ",cnt[i]);
 84     //printf("\n");
 85     for (int i=0;i<=n*m;++i)
 86         for (int j=0;j<1<<tot;++j)
 87             f[i][j]=0;
 88     f[0][0]=1;
 89     for (int i=1;i<=n*m;++i)
 90     {
 91         for (int j=0;j<1<<tot;++j)
 92         {
 93             f[i][j]=((ll)f[i-1][j]*((cnt[j]-(i-1))%MOD))%MOD;
 94             for (int k=j;k;k&=(k-1))
 95             {
 96                 x=k&(-k);
 97                 f[i][j]=((ll)f[i][j]+f[i-1][j-x])%MOD;
 98             }
 99         }
100     }
101     return f[n*m][(1<<tot)-1];
102 }
103
104 bool ok(int x,int y)
105 {
106     if (x<1||y<1||x>n||y>m) return false;
107     return true;
108 }
109
110 bool check()
111 {
112     int x,y;
113     for (int i=1;i<=n;++i)
114         for (int j=1;j<=m;++j)
115         {
116             if (a[i][j]!=‘X‘) continue;
117             for (int k=1;k<=8;++k)
118             {
119                 x=i+dx[k];
120                 y=j+dy[k];
121                 if (ok(x,y)&&a[x][y]==‘X‘) return false;
122             }
123         }
124     return true;
125 }

挫挫滴代码

时间: 2024-11-08 11:20:17

【noip模拟】局部最小值的相关文章

【noip模拟赛】 射击

这题似乎是什么安阳一中的模拟题,不管了,反正是学长出的noip模拟赛里面的题目.... 射击(shoot.pas/.c/.cpp) 时间限制:1s,内存限制128MB 题目描述: 据史书记载,对越反击战时期,有位中国侦察兵,他的代号叫814.一天他执行狙击任务,他的任务地区是n座恰巧在一条直线上的山.这些山所在直线恰巧为东西走向,山从东到西依次编号为1~n.一天814隐藏在编号为k的山上,每座山上都有1个目标. 814也非常的厉害,任务结束时杀了很多人,可是史书中只记载了两点: 1:814一定攻

NOIP模拟17.9.22

NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥ ??的位置去,但很不幸数轴上有??个区间是禁区,不能进入.青蛙会选择一个长度??,从原点开始每次向右跳长度为??的一段.一路上青蛙会停的位置是0, ??, 2??,…直到跳到了≥ ??的位置,任意一个位置都不能在禁区中.请求出??的最小值,注意??可以是实数.[输入格式]输入文件为susume.in.输入文件的第一行包含两个整数??和??,含义如问题描述中所述.接下来??行,每行描述一个禁区.每行有两个整数

关于过拟合、局部最小值、以及Poor Generalization的思考

Poor Generalization 这可能是实际中遇到的最多问题. 比如FC网络为什么效果比CNN差那么多啊,是不是陷入局部最小值啊?是不是过拟合啊?是不是欠拟合啊? 在操场跑步的时候,又从SVM角度思考了一下,我认为Poor Generalization属于过拟合范畴. 与我的论文 [深度神经网络在面部情感分析系统中的应用与改良] 的观点一致. SVM ImageNet 2012上出现了一个经典虐杀场景.见[知乎专栏] 里面有一段这么说道: 当时,大多数的研究小组还都在用传统compute

NOIP模拟17.8.17

NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 k 种字母.要求满足:• 字符串中相邻的两个字母不能相同.• 必须出现恰好 k 种不同的字母.这样的合法字符串可能有很多,小 L 让小 G 输出字典序最小的那个.小 G 太笨啦,不会做这道题,希望你帮帮他.[输入格

[BZOJ入门OJ2092][Noip模拟题]舞会

2092: [Noip模拟题]舞会 Time Limit: 20 Sec  Memory Limit: 256 MB Submit: 9  Solved: 5 [Submit][Status][Web Board] Description 学校举行舞会啦,一共有N个人参加,所有人站成一排,从左开始编号,最左边的人编号为1 ,最右边的为N.每个人跳舞的熟练度我们用一个整数表示,第i个人的熟练度为Ai,每次熟 练度最接近的一对相邻男女会出列跳舞,如果有多对那么最左边的那一对会先出列,请你给 出出列跳

【简单思考】noip模拟赛 NTR酋长

NTR酋长 (ntr.pas/.c/.cpp) 黄巨大终于如愿以偿的进入了czy的后宫中……但是czy很生气……他要在黄巨大走到他面前的必经之路上放上几个NTR酋长来阻挡黄巨大. 众所周知,NTR酋长有一个技能是沟壑(F).它会在地图上产生一条长长的障碍物阻挡人前进.Czy打算在一个n*m的矩形(必经之路?)中放上NTR酋长.NTR酋长要一个一个放下去,而且每放一个都会向四角倾斜的方向放出无限长的沟壑,而已经被沟壑挡住的地方就不能再放NTR酋长了. 请注意:不会出现沟壑的路径挡住另一个沟壑的情况

NOIP模拟赛

#1[Nescafé 31]杯NOIP模拟赛 t1 题意:n*m的棋盘上从(1,1)走到(n,m),只能向下或向右,一些格子有老鼠,每个老鼠互不相同,当处于与老鼠有重边的格子时,视为看见了这只老鼠,求到终点看到最少的不同老鼠数. 分析:DP 由于求得是看到的不同的老鼠数目,不能直接用过河卒做,因为同一个位置的老鼠可能会统计多次,我们还需要增加一维即方向. f[i,j,0]表示到从上面一个格子走到(i,j)时最少老鼠数,f[i,j,1]表示左边. f[i,j,0]:=min(f[i-1,j,0]+

NOIP模拟 17.8.18

NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也需要一定量的草作为饲料对于第 i头奶牛来说,它每天可以产 vi升的奶,同时需要 wi千克的草作为饲料现在来自蚯蚓国的九条可怜想借一些奶牛,使借走的这些奶牛每天的总产奶量最大,但九条可怜很穷,每天最多只能提供W千克的草作为饲料,而且她还需要对付跳蚤国的神刀手,所以她把这个问题交给了阿强巴,不不不……阿

NOIP模拟 6.28

NOIP模拟赛6.28 Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(type操作) 2.U x:撤销最后的x次修改操作.(Undo操作) (注意Query操作并不算修改操作) 3.Q x:询问当前文章中第x个字母并输出.(Query操作) 文章一开始可以视为空串. [输入格式]