bzoj 3916: friends 瞎搞

本文介绍了一种通过已知经过特定操作后的字符串U,逆向寻找原始字符串S的方法。问题转化为求两个子串的编辑距离为1的问题,并通过深度优先搜索(DFS)实现。文章给出了完整的C++代码实现及解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

有三个好朋友喜欢在一起玩游戏,A君写下一个字符串S,B君将其复制一遍得到T,C君在T的任意位置(包括首尾)插入一个字符得到U.现在你得到了U,请你找出S.

题解:

发现字符串的长度一定为奇数.
然后发现问题变成了
\(s[0 .. mid]\)\(s[mid+1 .. len]\)仅删除的编辑距离为1
或 : \(s[0 .. mid-1]\)\(s[mid .. len]\)仅删除的编辑距离为1

然后我们可以联想到以前的:电子词典
所以我们这道题可以直接暴力dfs查找..

不要忘记特判下标不同但本质相同的字符串.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 2000010;
char s[maxn];int ans,n,pos,del;
bool end_all1,end_all2;
void dfs1(int i,int j,bool f,int d){
    if(end_all1) return;
    if(i == pos+1){
        del = d;
            end_all1 = true; 
        ++ ans;
        return;
    }
    if(s[i] != s[j] || j == n){
        if(f) dfs1(i+1,j,false,i);
        else return;
    }else{
        dfs1(i+1,j+1,f,d);
        if(f) dfs1(i+1,j,false,i);
    }
}
void dfs2(int i,int j,bool f,int d){
    if(end_all2) return;
    if(i == n){
        del = d;
        end_all2 = true; 
        ++ ans;
        return;
    }
    if(s[i] != s[j] || j == pos){
        if(f) dfs2(i+1,j,false,i);
        else return;
    }else{
        dfs2(i+1,j+1,f,d);
        if(f && i != pos) dfs2(i+1,j,false,i);
    }
}
int main(){
    read(n);
    if(n % 2 == 0 || n == 1) return puts("NOT POSSIBLE");
    pos = (n>>1);scanf("%s",s);
    dfs1(0,pos+1,true,0);
    if(s[pos] == s[0]) dfs2(pos+1,1,true,0);
    if(ans == 2){
        int i;
        for(i=0;i<pos && s[i] == s[pos+i+1];++i);
        if(i < pos) puts("NOT UNIQUE");
        else for(int i=0;i<pos;++i) putchar(s[i]);
    }
    else if(ans == 0) puts("NOT POSSIBLE");
    else{
        if(del < pos){
            for(int i=0;i<=pos;++i){
                if(del == i) continue;
                putchar(s[i]);
            }
        }else{
            for(int i=pos;i<n;++i){
                if(del == i) continue;
                putchar(s[i]);
            }
        }
        puts("");
    }
    getchar();getchar();
    return 0;
}

转载于:https://www.cnblogs.com/Skyminer/p/6568435.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值