首页 > 其他分享 >P9013 [USACO23JAN] Find and Replace S

P9013 [USACO23JAN] Find and Replace S

时间:2023-09-22 20:56:55浏览次数:44  
标签:字符 P9013 nxt int memset vis USACO23JAN sizeof Find

前言

这是考试的时候放的一道题,考的时候没做出来。

调了一个晚上,心态爆炸,故作此篇。顺便,鸣谢泥土笨笨大佬的题解,给我的代码提供了强有力的对拍参照。

正题

首先看到题目,虽然字符串长度不超过 \(10^5\),但是还是嫌多;再一看,至多只有52个字符

那么从这个数据范围入手,思考可以按照变换前后的字符串给所有字符建一张图,其中的每一条有向边 \(a \rightarrow b\) 表示变换前的字符 \(a\) 变成了字符 \(b\)。接下来思考这个图可能有哪几种形式:

首先讨论 1:显然无解!一个字符不可能同时分裂成两种不同的字符。所以,我们得到了第一种无解的判定。

其次讨论形成一条链(2):显然的,假设这条链有 \(n\) 条边,可以在 \(n\) 次转化后完成。

然后是一个环(3):这就无法用 \(n\) 次完成了,必须先将某个点换成另一种字符,转化成一条有 \(n+1\) 个节点的链来做,所以要 \(n+1\) 次完成。

最后是生出尾巴的环(4):刹一看,好像要 \(n+1\) 次完成;其实不用。把入度为 \(2\) 的点叫做点 \(a\),尾巴上指向 \(a\) 的点是 \(b\),环上指向 \(a\) 的是 \(c\),可以现将点 \(c\) 换成字符 \(a\),转换成一条 \(n\) 的链,最后 \(c\) 和 \(a\) 一起变成 \(b\)。所以也是只用 \(n\) 次。

当然,实际处理中这三种总是会一起出现(2,3,4),那么只要意义处理就行。

除了上面提到的第一种无解,还有一种情况就是转换后的字符串包含了所有的字符(\(52\) 个),并且和转换前的字符串不同。这时候,若画出图来应该是一个 \(52\) 个点的环,由于没有一个点可以变成另一个不同于这 \(52\) 个点的字符,所以也是无解。

那么代码就好实现了。不过这里有几点需要注意:

  • 从入度小的点开始遍历图,而不是按照字母顺序。

  • 判断一个字符是否要同事变成两个字符时,别忘了把它自己算上。

接下来是代码时间(写法丑陋,仅作参考):

#include <bits/stdc++.h>
using namespace std;
int nxt[55],id[128],ans,T;
bool vis[55],has[55],noind[55];
char s1[100005],s2[100005];
void init() {
    ans=0;
    memset(nxt,0,sizeof(nxt));
    memset(vis,false,sizeof(vis));
    memset(has,false,sizeof(has));
    memset(noind,true,sizeof(noind));
    memset(s1,0,sizeof(s1));
    memset(s2,0,sizeof(s2));
    return ;
}
void addans(int p) {
    if(vis[p]) return ;
    int v=p,type=0;
    vis[p]=true;
    while(nxt[v]) {
        type++,v=nxt[v];
        if(v==p) {
            ans+=type+1;
            return ;
        }
        if(vis[v]) {
            ans+=type;
            return ;
        }
        vis[v]=true;
    }
    ans+=type;
    return ;
}
int main() {
    scanf("%d",&T);
    for(int i=0;i<26;i++) id[i+'A']=i+1,id[i+'a']=i+27;
//    for(int i='A';i<='Z';i++) cout<<char(i)<<":"<<id[i]<<endl;
//    for(int i='a';i<='z';i++) cout<<char(i)<<":"<<id[i]<<endl;
    while(T--) {
        init();
        scanf("%s%s",s1+1,s2+1);
        int len=strlen(s1+1);
        bool no_ans=false,same=true;
        set<char> chset;
        for(int i=1;i<=len;i++) {
            int id1=id[s1[i]],id2=id[s2[i]];
            if(has[id1]&&(id2!=nxt[id1])) {
                no_ans=true;
                break;
            }
            else {
                has[id1]=true,nxt[id1]=id2;
                if(id1!=id2) noind[id2]=false,same=false;;
            }
            chset.insert(s2[i]);
        }
        if(same) {
            printf("0\n");
            continue;
        }
        for(int i=1;i<=52;i++)
            if(nxt[i]==i) nxt[i]=0;
        for(int i=1;i<=52;i++)
            if(noind[i]) addans(i);
        for(int i=1;i<=52;i++)
            if(has[i]) addans(i);
        if(no_ans) printf("-1\n");
        else if(chset.size()==52) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}

完结撒花!!!

标签:字符,P9013,nxt,int,memset,vis,USACO23JAN,sizeof,Find
From: https://www.cnblogs.com/TimelessWelkinBlog/p/17723336.html

相关文章

  • linux 中 find命令 -maxdepth 和 -mindepth 选项
     001、[root@pc1dir001]#lstest01test02ww.txtxx.map[root@pc1dir001]#tree.├──test01│  ├──cc.csv│  └──kk.txt├──test02│  ├──dirxx│  │  └──diryy│  │  ├──rr.ped│  │  └......
  • 题解 P9019 [USACO23JAN] Tractor Paths P
    显然,对于给定的\(l,r\),最短路可以贪心求出,即每次走与当前区间相交且左端点最大的区间,这个可以用倍增加速。定义\(f_{i,j}\)表示从区间\(i\)往右走\(j\)步后到达的区间,\(g_{i,j}\)表示往左走的情况。正反遍历一下即可求出\(f_{i,1}\)和\(g_{i,1}\)。对于第二问,第\(i......
  • FIND_IN_SET() INSTR()
    FIND_IN_SET(str,strlist)函数功能查找str在strlist中的位置注意事项find_in_set()函数是精确匹配多个空格也会匹配不上INSTR(源字符串,目标字符串)函数功能字符查找函数。获取子串第一次出现的索引,如果没有找到,则返回0(从1开始)。相较于find_in_set()函数instr......
  • linux中grep与find的区别,Linux三剑客【grep、sed和awk】
    在使用linux时,经常需要进行文件查找。其中查找的命令主要有find和grep。两个命令是有区的。区别:(1)find命令是根据文件的属性进行查找,如文件名,文件大小,所有者,所属组,是否为空,访问时间,修改时间等。(2)grep是根据文件的内容进行查找,会对文件的每一行按照给定的模式(patter)......
  • Linux中find命令的prune参数探究
     记得很久之前找过prune的参数使用,应急用了之后没有记录,但过了一段时间就会忘记,这次趁机找了一圈,包括Google-aosp里面的用法也对比参照了一下。 参考https://www.jianshu.com/p/e0a9fb35601a 发现描述基本没问题,使用上还有些差异,特此记录一下:<以下主要是 -prune-o-p......
  • find
     [root@pc1test2]#lsa.txtb.csvc.pedtest_dir[root@pc1test2]#lstest_dir/[root@pc1test2]#find./-name"*.txt"-o-name"*.ped"-execcp{}test_dir/\;[root@pc1test2]#lstest_dir/c.ped[root@pc1test2]#rmtest_dir/......
  • spring boot 在Linux下服务启动报错Unable to find Java
    前言:最近在开发项目的过程中遇到了一些坑(也可能不是坑,是自己没弄过导致折腾了很久),我们项目中遇到有用到一些第三方的库,有些第三方库可能不支持openjdk,只支出jdk,所以就要更换一下jdk,然后服务器又是之前的前同事配置的,这时候我把服务器的jdk版本从原来的openjdk1.7换成了官方的......
  • KingbaseES V8R6集群备份恢复案例之---备份初始化“can not find primary node”故障
    案例说明:KingbaseESV8R6集群,备库作为repo-path节点,建立类型为‘cluster’模式的备份,在执行sys_backup.shinit时,出现“cannotfindprimarynode”故障。故障如下图所示:适用版本:KingbaseESV8R6一、集群及备份配置1、集群节点状态[kingbase@node101bin]$./repmgrclus......
  • 【ERROR: Could not find a version that satisfies】【ERROR: No matching distribut
    pip包安装出错真是把我烦死了,在yt上学东西,结果一直出这样的错,之前我都是把包下载到本地安装的,这也不是长久之计。然后我试了使用-i,使用--trusted-host,使用--user,使用--upgradepip...全都不管用。后来我想,究竟是什么时候出现这个问题的,好像很久之前就有了...老提示不安全的连......
  • WebStrom提交代码到GitLab报错Error: Cannot find any-observable implementation nor
    项目场景:前端代码完成后,提交代码问题描述提交代码到GitLab时,因自动检测机制导致项目提交失败C:\D\insper\inspur_works\custom-manage-front\node_modules\any-observable\register.js:29 thrownewError('Cannotfindany-observableimplementationnor'+ ^Error:C......