可以发现行和列其实没什么关系,于是我们愉快地分开处理,最后相乘。
比如说现在在处理纵向的折痕:
我们先把每列压成一个数,存入数组
,这样就可以O(1)比较两列是否相等。
然后我们再预处理出
,表示以
为中心的回文长度。
再用
表示折成第
列到第
列是否可行,枚举折在哪里即可。
复杂度
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=51;
int n,m;
int dp[N][N];
int f[N];
ll a[N];
template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; }
template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; }
class BoardFoldingDiv2 {
public:
int howMany( vector <string> paper ) ;
};
int solve(int n){
for(int i=0;i<n-1;i++){
int j=i,k=i+1;
for(f[i]=0;j>=0&&k<n&&a[j]==a[k];j--,k++) f[i]++;
}
memset(dp,0,sizeof dp);
dp[0][n-1]=1;
for(int i=0;i<n;i++)
for(int j=n-1;j>=i;j--)
if (dp[i][j])
for(int k=i;k<j;k++)
if (f[k]>=k-i+1||f[k]>=j-k){
if (k-i+1<=j-k) dp[k+1][j]=1;
if (j-k<=k-i+1) dp[i][k]=1;
}
int ans=0;
for(int i=0;i<n;i++)
for(int j=n-1;j>=i;j--)
if (dp[i][j]) ans++;
return ans;
}
int BoardFoldingDiv2::howMany(vector <string> c) {
n=c.size();m=c[0].size();
memset(a,0,sizeof a);
for(int j=0;j<m;j++)
for(int i=0;i<n;i++)
a[j]=(a[j]<<1)+c[i][j]-'0';
int ans=solve(m);
memset(a,0,sizeof a);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
a[i]=(a[i]<<1)+c[i][j]-'0';
return solve(n)*ans;
}