Codeforces 845F Guards In The Storehouse
2017-09-01 11:32
183 查看
原题
Codeforces845F题意
给一个n*m的格子,每个格子是空地或者墙。一个守卫( x , y )可以保护的范围包括x0>=x,y0==y和x0==x,y0>=y的没有被墙壁遮挡所有点。
守卫只能放置在空地上。
求有多少种放置守卫的方法,使至多一个格子没有被任何守卫保护。
解题思路
对于一块空地( x , y ),如果放置守卫,影响的点一定是确定的。假设我们按以下方式给每个格子编号。
1 | 4 | 7 | 10 |
2 | 5 | 8 | 11 |
3 | 6 | 9 | 12 |
假设我们是从左到右、从上到下地计算的,相当于我们是从左到右一列一列地计算答案。那么我们就只需要知道当前位置是否会被当前列之前放置的守卫影响,这个状态只有0/1两种。
但是对于行来说,我们需要知道每一行之前放置的守卫是否会对当前位置产生影响。因为我们是一列一列的计算,无法连续计算的同一行,因此需要记录下每一行的状态,因此这个状态有2n。
然而我们只知道n<=250和m*n<=250,因此2n可能会很大。
但我们可以整个图旋转一下,使n为原来的min( n , m )。因为m*n<=250,因此min( n , m )<=sqrt(250),即min( n , m )<=15。
这样2n的状态就是能接受的了。
因为答案所求是未被守卫的格子至多只有一个,于是我们可以定义一个0/1的状态表示是否已经有一个为被守卫的格子。
于是我们就可以这样表示状态。
f[pos][s][op1][op2]表示当前我们在pos位置,行被覆盖的情况为s,op1为是否当前列被覆盖,op2为是否已经有一个位置未被覆盖。
状态转移的时候注意遇到墙的时候需要对行和列的覆盖情况都进行修改,注意从一列到另一列的时候需要清空op1。
状态转移详见代码。
#include <cstdio> #include <algorithm> using namespace std; const int N=260,Mod=1e9+7; int n,m; int f [(1<<15)+10][2][2]; bool map ; bool Get() { char ch=getchar(); while (ch!='.' && ch!='x') ch=getchar(); if (ch=='.') return 0;else return 1; } void Init() { scanf("%d%d",&n,&m); if (n<=m) for (int i=0;i<n;++i) for (int j=0;j<m;++j) map[j*n+i]=Get(); else { for (int i=0;i<n;++i) for (int j=0;j<m;++j) map[i*m+j]=Get(); swap(n,m); } } void Solve() { int Max=1<<n; f[0][0][0][0]=1; int node=0; for (int i=0;i<m;++i) for (int j=0;j<n;++j) { for (int s=0;s<Max;++s) for (int op1=0;op1<2;++op1) for (int op2=0;op2<2;++op2) { if (!f[node][s][op1][op2]) continue; if (map[node]) { int now; if (s&(1<<j)) now=s^(1<<j);else now=s; f[node+1][now][0][op2]=(f[node+1][now][0][op2]+f[node][s][op1][op2])%Mod; }else { int tp1; if (j==n-1) tp1=0;else tp1=op1; if (s&(1<<j) || op1) f[node+1][s][tp1][op2]=(f[node+1][s][tp1][op2]+f[node][s][op1][op2])%Mod; else if (!op2) f[node+1][s][tp1][1]=(f[node+1][s][tp1][1]+f[node][s][op1][op2])%Mod; if (j==n-1) tp1=0;else tp1=1; f[node+1][s|(1<<j)][tp1][op2]=(f[node+1][s|(1<<j)][tp1][op2]+f[node][s][op1][op2])%Mod; } } node++; } int ans=0; for (int i=0;i<Max;++i) for (int op1=0;op1<2;++op1) for (int op2=0;op2<2;++op2) if (f[node][i][op1][op2]) ans=(ans+f[node][i][op1][op2])%Mod; printf("%d\n",ans); } int main() { Init(); Solve(); return 0; }
相关文章推荐
- CodeForces - 192A Funky Numbers
- codeforces 401D Roman and Numbers (数位dp)
- CodeForces 632C - C. The Smallest String Concatenation
- codeforces 671C
- codeforces 455B A Lot of Games
- Codeforces 272C Dima and Staircase
- CodeForces 845C Two TVs
- CodeForces - 598C 598D //Nearest vectors// Igor In the Museum
- (CodeForces - 600C)Make Palindrome
- CodeForces 177(div1)B
- CodeForces 762F. Tree nesting
- Codeforces 220B - Little Elephant and Array 离线树状数组
- python codeforces 322 div2 C
- Codeforces 918A Eleven
- Codeforces 302(div1)
- Codeforces 854A Fraction
- Codeforces 612C Replace To Make Regular Bracket Sequence 【stack】
- Codeforces 762A-k-th divisor
- codeforces 459C Pashmak and Buses(模拟,组合数A)
- codeforces 583B Robot's Task