【学习笔记】CF613E Puzzle Lover

这题本质上还是数据结构。

首先看到这个 2 × n 2\times n 2×n的网格图就很容易想到分治。我们还是考虑把要统计的东西变得可视化,一条路径要么穿过中线一次,那么我们可以将两边的串拼起来得到答案;要么穿过中线两次,考虑其中一边的路径是固定的,那么我们枚举两个端点再判断一下和原串是否匹配的上就做完了。那么考虑预处理出 d p i , j , 0 / 1 , 0 / 1 dp_{i,j,0/1,0/1} dpi,j,0/1,0/1表示从位置 ( 1 / 2 , i ) (1/2,i) (1/2,i)开始,匹配长度为 j j j,向左/右走的方案数,这事实上非常好转移,可以自己编一下。当然可能还要把串正着和倒着处理一边,总之挺麻烦的。

将网格图翻转后做两次即可得到答案。求 L c p Lcp Lcp可以用暴力 d p dp dp代替。事实上也并不需要分治。注意不要算重

细节题,贼容易写挂。

复杂度 O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f
#define db double
#define cpx complex<db>
using namespace std;
const int mod=1e9+7;
const int N=2005;
int n,K,Right[2][N][N],Left[2][N][N],dpl[2][N][N],res;
string s[2],str;
void add(int &x,int y){
    x=(x+y)%mod;
}
void solve(){
    for(int i=0;i<2;i++){
        for(int j=n-1;j>=0;j--){
            for(int k=0;k<K;k++){
                Right[i][j][k]=(s[i][j]!=str[k])?0:((j!=n-1&&k>=1)?(Right[i][j+1][k-1]+1):1);
            }
        }
    }
    for(int i=0;i<2;i++){
        for(int j=0;j<n;j++){
            for(int k=0;k<K;k++){
                Left[i][j][k]=(s[i][j]!=str[k])?0:((j>=1&&k>=1)?(Left[i][j-1][k-1]+1):1);
            }
        }
    }
    memset(dpl,0,sizeof dpl);
    for(int i=0;i<2;i++){
        for(int j=0;j<n;j++){
            if(s[i][j]==str[0]){
                dpl[i][j][0]=1;
            }
        }
    }
    //fixed
    for(int i=0;i<n;i++){
        for(int j=i;j<n;j++){
            for(int k=0;k<2;k++){
                //strange
                if(Left[k][j][2*(j-i+1)-1]>=j-i+1&&Right[k^1][i][j-i]>=j-i+1){
                    add(dpl[k][j][2*(j-i+1)-1],1);
                }
            }
        }
    }
    for(int k=1;k<K;k++){
        for(int i=0;i<2;i++){
            for(int j=0;j<n;j++){
                if(s[i][j]==str[k]){
                    if(j)add(dpl[i][j][k],dpl[i][j-1][k-1]);
                    if(s[i^1][j]==str[k-1]){
                        if(j&&k-2>=0)add(dpl[i][j][k],dpl[i^1][j-1][k-2]);
                    }
                }
            }
        }
    }
}
void getans(){
    //fixed
    for(int i=0;i<2;i++){
        for(int j=0;j<n;j++){
            add(res,dpl[i][j][K-1]);
        }
    }
    for(int i=1;i<n;i++){
        for(int j=i+1;j<n;j++){
            for(int k=0;k<2;k++){
                if(Right[k][i][K-1]>=j-i+1&&K-(j-i+2)>=0&&Left[k^1][j][K-(j-i+2)]>=j-i+1&&K-2*(j-i+1)-1>=0){
                    add(res,dpl[k^1][i-1][K-2*(j-i+1)-1]);
                }
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>s[0]>>s[1]>>str,n=s[0].size(),K=str.size();
    //fixed
    if(K==1){
        for(int i=0;i<2;i++){
            for(int j=0;j<n;j++){
                if(s[i][j]==str[0]){
                    add(res,1);
                }
            }
        }
        cout<<res;
        return 0;
    }
    if(K==2){
        for(int i=0;i<2;i++){
            for(int j=0;j<n-1;j++){
                if(s[i][j]==str[0]&&s[i][j+1]==str[1]){
                    add(res,1);
                }
                if(s[i][j+1]==str[0]&&s[i][j]==str[1]){
                    add(res,1);
                }
            }
        }
        for(int i=0;i<2;i++){
            for(int j=0;j<n;j++){
                if(s[i][j]==str[0]&&s[i^1][j]==str[1]){
                    add(res,1);
                }
            }
        }
        cout<<res;
        return 0;
    }
    //fixed
    solve();
    getans();
    //fixed
    swap(s[0],s[1]),reverse(s[0].begin(),s[0].end()),reverse(s[1].begin(),s[1].end());
    solve();
    getans();
    cout<<res<<"\n";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值