TopCoder SRM 639 DIv2 1000 BoardFoldingDiv2

可以发现行和列其实没什么关系,于是我们愉快地分开处理,最后相乘。

比如说现在在处理纵向的折痕:
我们先把每列压成一个数,存入数组 a ,这样就可以O(1)比较两列是否相等。
然后我们再预处理出 f [ i ] ,表示以 i , i + 1 为中心的回文长度。
再用 d p [ i ] [ j ] 表示折成第 i 列到第 j 列是否可行,枚举折在哪里即可。

复杂度 O ( n 3 )

#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;
}

猜你喜欢

转载自blog.csdn.net/ymzqwq/article/details/82492006