uva 11468-Substring ac自动机 + 记忆化搜索

本文介绍了一种使用AC自动机结合记忆化搜索解决UVA11468问题的方法,该问题要求计算给定模式串集及每步字符选择概率下,生成特定长度字符串而不包含任何模式串的概率。

题目大意:给定k个模式串,然后给定在每一步中字母被选中的概率,求获得长度为L的字符串的且其中不包含任何模式串的概率是多少。

 此题既然给定的是模式串,我们首先想到肯定是要建立自动机,但是建立自动机之后该怎么办呢?

这里就要思考,符合题意的串到底该如何求得呢?

ac自动机说道底就是状态的转换。在构造串时就是没每一步选择一个字符,一旦选择了这个字符,那么现在的串的任何后缀不能是任何模式串。因为如果某个后缀是某个模式串,那么肯定不符合题意啊。所以,此题就是在当前字符串在的ac自动机的那个状态上,选择下一个字母,且满足选择的下一个字母与当前字符串组合之后的字符串的任何后缀不是某个模式串。到此使用的算法也就是搜索,以ac自动的状态为当前节点,遍历下一个可以取的字符。同时加个记忆化。


//
//  main.cpp
//  uva 11468 SubString---AC自动机
//
//  Created by XD on 15/8/31.
//  Copyright (c) 2015年 XD. All rights reserved.
//
//ac自动机 + 加记忆化搜索

#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<vector>
#include <string.h>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
using namespace std ;
const int maxn =410 ;
const int sigma_size  = 65 ;
double prob[65  ] ;
struct Ahocrosickautomata
{
    int ch[maxn][sigma_size] ;
    int sz , f[maxn] , match[maxn] ;
    void init()
    {
        sz = 1 ;
        memset(ch[0], 0, sizeof(ch[0])) ;
        match[0]  =0 ;
    }
    int idx(char ch)
    {
        if(ch >='A'&& ch<='Z') return ch-'A' ;
        else if (ch >='a'&&ch <= 'z') return ch - 'a' + 26;
        else return ch - '0'  + 52 ;
    }
    void insert(char *s,int v)
    {
        int u = 0 ;
        int len = (int)strlen(s) ;
        for(int i = 0 ; i < len ; i++)
        {
            int j = idx(s[i] );
            if(!ch[u][j])
            {
                memset(ch[sz], 0, sizeof(ch[sz])) ;
                match[sz] = 0 ;
                ch[u][j] = sz++ ;
                
            }
            u = ch[u][j] ;
        }
        match[u]  = v ;
    }
    void getFail()
    {
        f[0] = 0 ;
        queue<int > q ;
        for(int i = 0 ; i < sigma_size ; i++)
        {
            int u  =ch[0][i] ;
            if(u) {f[u]  =0  ; q.push(u) ; }
            
        }
        while(!q.empty())
        {
            int r = q.front() ;q.pop() ;
            for(int i = 0 ; i < sigma_size ;i++)
            {
                int u  =ch[r][i] ;
                if(!u) {ch[r][i] = ch[f[r]][i] ; continue;}
                q.push(u) ;
                int v = f[r] ;
                while(v && !ch[v][i]) v = f[v] ;
                f[u] =ch[v][i] ;
                match[u]  |= match[f[u]] ;
            }
        }
    }
    
    
};
Ahocrosickautomata ac ;
int vis[maxn][110] ;
double d[maxn][110] ;
vector<char> alph ;
double getProb(int u ,int L)
{
    if (!L) {
        return 1.0 ;
    }
    if(vis[u][L]) return d[u][L] ;
    vis[u][L] = 1 ;
    double ans = 0 ; d[u][L] = 0 ;
    int len =(int )alph.size() ;
    for (int i = 0 ; i < len ; i++) {
        int v = ac.ch[u][ac.idx(alph[i])]  ;
        if (!ac.match[v]) {
            ans += prob[ac.idx(alph[i])] * getProb(v, L-1) ;
        }
    }
    d[u][L] = ans ;
    return ans ;
}
int main(int argc, const char * argv[]) {
    int  T ; scanf("%d" ,&T) ;
    char c ;int kase = 0,L ;
    char s[25] ;
    while (T--) {
        alph.clear() ;
        ac.init() ;
        int k,n  ;
        scanf("%d" ,&k) ;
        for (int i = 0 ; i < k ; i++) {
            scanf("%s" ,s) ;
            ac.insert(s, 1) ;
        }
        ac.getFail() ;
        scanf("%d" ,&n) ;
        for (int i = 0 ; i < n  ; i++) {
//            scanf(" %c%lf" ,&c , &prob[ac.idx(c)]) ;
            getchar() ;
            scanf("%c" , &c) ;
            scanf("%lf"  ,&prob[ac.idx(c)]) ;
            alph.push_back(c) ;
        }
        memset(vis, 0, sizeof(vis)) ;
        
        scanf("%d" , &L) ;
        printf("Case #%d: %.6lf\n" , ++kase , getProb(0 , L)) ;
        
    }
        return 0;
}


内容概要:本文详细介绍了“秒杀商城”微服务架构的设计与实战全过程,涵盖系统从需求分析、服务拆分、技术选型到核心功能开发、分布式事务处理、容器化部署及监控链路追踪的完整流程。重点解决了高并发场景下的超卖问题,采用Redis预减库存、消息队列削峰、数据库乐观锁等手段保障数据一致性,并通过Nacos实现服务注册发现与配置管理,利用Seata处理跨服务分布式事务,结合RabbitMQ实现异步下单,提升系统吞吐能力。同时,项目支持Docker Compose快速部署和Kubernetes生产级编排,集成Sleuth+Zipkin链路追踪与Prometheus+Grafana监控体系,构建可观测性强的微服务系统。; 适合人群:具备Java基础和Spring Boot开发经验,熟悉微服务基本概念的中高级研发人员,尤其是希望深入理解高并发系统设计、分布式事务、服务治理等核心技术的开发者;适合工作2-5年、有志于转型微服务或提升架构能力的工程师; 使用场景及目标:①学习如何基于Spring Cloud Alibaba构建完整的微服务项目;②掌握秒杀场景下高并发、超卖控制、异步化、削峰填谷等关键技术方案;③实践分布式事务(Seata)、服务熔断降级、链路追踪、统一配置中心等企业级中间件的应用;④完成从本地开发到容器化部署的全流程落地; 阅读建议:建议按照文档提供的七个阶段循序渐进地动手实践,重点关注秒杀流程设计、服务间通信机制、分布式事务实现和系统性能优化部分,结合代码调试与监控工具深入理解各组件协作原理,真正掌握高并发微服务系统的构建能力。
<think>嗯,用户需要将employee表中的Name字段转换为首字母大写,其余小写的格式。首先,我得想一下SQL中有没有内置的函数可以直接处理这种情况。比如,MySQL有没有类似的首字母大写的函数?记得好像有INITCAP函数,但可能是在Oracle里,MySQL可能不支持。 那如果MySQL不支持的话,可能需要用其他函数组合来实现。比如,先取出第一个字符,转换为大写,然后剩下的字符转换为小写,再拼接起来。对了,SUBSTRING函数可以截取字符串的一部分,UPPER和LOWER函数可以转换大小写。例如,第一个字符用UPPER(SUBSTRING(Name,1,1)),然后剩下的部分用LOWER(SUBSTRING(Name,2)),然后用CONCAT把它们连起来。 不过,如果名字中间有空格或者连字符,比如“mary-ann”或者“o'neil”,这种情况下可能需要更复杂的处理。但用户的问题可能只是简单的首字母大写,其余小写,暂时不考虑中间的特殊情况。所以基础方法应该能满足大部分情况。 另外,不同的数据库系统可能有不同的函数,比如SQL Server可以使用CONCAT和UPPER/LOWER,而PostgreSQL可能有INITCAP函数,但INITCAP可能会把每个单词的首字母都大写,而用户可能只需要整个字段的首字母大写。所以需要确认需求是整个字段的首字母还是每个单词的首字母。用户的问题描述是“首字母大写其余小写”,应该是指整个字段的第一个字母大写,其余都小写,不管中间是否有空格。例如,“john doe”变成“John doe”?还是每个单词的首字母都大写?这里可能需要进一步确认,但根据问题描述,可能用户需要的是整个字段的首字母大写,其余小写。比如,如果原数据是“jOHN”,结果应该是“John”。 那在MySQL中,可能需要用CONCAT加上SUBSTRING来处理。例如: SELECT CONCAT(UPPER(SUBSTRING(Name,1,1)), LOWER(SUBSTRING(Name,2))) AS FormattedName FROM employee; 这样应该可以处理大部分情况,但如果字段长度为0或者NULL的话,可能需要处理异常情况,比如使用CASE语句或者IF函数来判断长度是否大于0。 另外,如果名字中间有空格,可能需要分开处理每个单词,但根据用户的问题描述,可能不需要这么复杂。所以先给出基础解决方案,再提到可能的限制和特殊情况。 总结一下,步骤应该是: 1. 截取第一个字符并转为大写。 2. 截取剩余字符转为小写。 3. 拼接两部分。 4. 处理可能的空值或异常情况。</think>以下是实现该功能的SQL代码示例: ```sql SELECT CONCAT( UPPER(SUBSTRING(Name, 1, 1)), LOWER(SUBSTRING(Name, 2)) ) AS FormattedName FROM employee; ``` ### 实现原理分步说明: 1. **SUBSTRING(Name,1,1)** 截取姓名字段的第一个字符 2. **UPPER()** 将首字母转换为大写 3. **SUBSTRING(Name,2)** 截取首字母之后的所有字符 4. **LOWER()** 将后续字符转换为小写 5. **CONCAT()** 拼接处理后的首字母和后续字符 ### 特殊注意事项: - 当字段值为空时会返回空值 - 适用于单字名字(如"JOHN"转"John") - 对含空格的名字(如"john doe"会转"John doe")需要额外处理[^2] - 支持MySQL、PostgreSQL、SQL Server等主流数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值