题意:
给一个n*m的矩阵, 'o' 表示可以将此格子变成 蓝格子 或 红格子 . 在一行中两个相邻的蓝格子可以放置一个 1*2 的矩阵块 ,在一列中两个相邻的红格子可以放置一个 1*2 的矩阵块. 求所有方案中可以放置1*2矩阵块的最大数量.每种方案都是放置矩阵块最优的.
思路:
可以确定,行和列的贡献是互不干扰的.所以可以先分析出 所有行所产生的贡献
设一段连续的 'o' 产生的本质贡献是 p, 'o'的数量是cnt . 矩阵中'o'的数量是 sum ;
对于一行中连续的一段'o', 其他所有的'o'是不会对这一段产生的本质贡献 p 产生干扰,也就是说除了这一段的'o',其他的'o'是可以随意变换的.
那么这一段'o'所产生的总贡献是 p*pow(2,sum-cnt);
现在问题就转化成了 求一段连续的'o'的贡献
设dp[i] 为 长度为 i 的'o'所有方案可以放置的矩阵总数
假设现在有长度为 4 的'o' : oooo 求dp[5]
//为了表示方便,0 代表将'o' 变成红格子, 1代表将'o'变成蓝格子 11就表示可以放一个1*2矩阵
若我们将第五个格子变成'0' 即 oooo0 ,并不会对先前已产生的方案数造成影响,加上即可==> +dp[i-1]
若我们将第五个格子变成'1' 即oooo1 ,此时若第4个格子为1,那么会产生新的方案.需要将4,5号格子看成一体(并不会影响最优放置).将4,5号格子看成一体后,4号格子就有两种情况,就需要加上2倍的dp[i-2] ==>+2*dp[i-2]
若4,5号格子为(1,1) 我们还需要计算(1,1)产生的贡献,即 pow(2,cnt-2) //前3个格子随意选择
递归方程为 : dp[i]=dp[i-1]+dp[i-2]*2+pow(2,i-2);
参考代码:
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int qs=3e5+7; 5 const ll mod=998244353; 6 ll dp[qs],f[qs]; 7 ll n,m; 8 string s[qs]; 9 int main(){ 10 std::ios::sync_with_stdio(false); 11 cin>>n>>m; 12 for(int i=0;i<n;++i) cin>>s[i]; 13 dp[1]=dp[0]=0; f[0]=1,f[1]=2; 14 for(int i=2;i<=qs-6;++i){ 15 dp[i]=((dp[i-1]+f[i-2])%mod+dp[i-2]*2%mod)%mod; 16 f[i]=2*f[i-1]%mod; 17 } 18 ll cnt=0,a1=0,a2=0,ans,sum=0; 19 for(int i=0;i<n;++i) 20 for(int j=0;j<m;++j) if(s[i][j]=='o') sum++; 21 for(int i=0;i<n;++i){ 22 for(int j=0;j<m;++j){ 23 if(s[i][j]=='o') ++cnt; 24 if(s[i][j]!='o'||j==m-1){ 25 if(cnt==1){ 26 cnt=0; continue; 27 } 28 a1=a1+dp[cnt]%mod*f[sum-cnt]%mod; 29 a1%=mod; 30 cnt=0; 31 } 32 } 33 } 34 cnt=0; 35 for(int j=0;j<m;++j){ 36 for(int i=0;i<n;++i){ 37 if(s[i][j]=='o') ++cnt; 38 if(s[i][j]!='o'||i==n-1){ 39 if(cnt==1){ 40 cnt=0; continue; 41 } 42 a2=a2+dp[cnt]%mod*f[sum-cnt]%mod; 43 a2%=mod; 44 cnt=0; 45 } 46 } 47 } 48 ans=(a1+a2)%mod; 49 cout<<ans<<" "; 50 return 0; 51 }
//QAQ