洛谷试炼日记(trie树,AC自动机,回文自动机)(解题报告)

Trie树

P4683 [IOI2008] Type Printer 打印机

题目链接
就是求最小操作数嘛 一开始想太多,其实就是最长的最后打印呗
那就先标记一下最长的那一串 然后dfs先跳过那些最长串经过的节点
最后再枚举最长串的节点就行啦
细节看代码(也没啥细节啦
AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 5e6 + 10;
int ch[N][26],cnt,fl[N],mx[N];
string s,a,ss;char t[N];
int n,tot;

template <class T>
inline void read(T& x){
    x = 0;int f = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48),c = getchar();
    x *= f;
}

void insert(string s){
    int u = 0;
    for(int i = 0;s[i];i ++){
        int v = s[i] - 'a';
        if(!ch[u][v]) ch[u][v] = ++ cnt;
        u = ch[u][v];
        t[u] = v + 'a';
    }
    fl[u] = 1;
}

void dfs(string a){
    int u = 0;
    for(int i = 0;a[i];i ++){
        u = ch[u][a[i] - 'a'];
        mx[u] = 1;
    }
}

void solve(int u){
    if(fl[u]){
        tot ++;
        ss += 'P';
    }
    if(tot == n){
        cout << ss.size() << endl;
        for(int i = 0;ss[i];i ++){
            cout << ss[i] << endl;
        }
        return;
    }

    for(int i = 0;i < 26;i ++){
        if(ch[u][i] && !mx[ch[u][i]]){
            ss += t[ch[u][i]];
            solve(ch[u][i]);
            ss += '-';
        }
    }
    for(int i = 0;i < 26;i ++){
        if(ch[u][i] && mx[ch[u][i]]){
            ss += t[ch[u][i]];
            solve(ch[u][i]);
            ss += '-';
        }
    }
}
int main(){
    read(n);
    int mxl = 0;
    for(int i = 0;i < n;i ++){
        cin >> s;
        insert(s);
        if(mxl < s.size()){
            mxl = s.size();
            a = s;
        }
    }
    dfs(a);
    solve(0);
    return 0;
}

AC自动机

P2444 [POI2000]病毒

题目链接
fail跳来跳去挺好玩的,不这道题咱不跳fail
我们标记一下病毒串,然后在trie图上判断是否存在一个环,且环上没有病毒标记
dfs判环就行啦
AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>

using namespace std;
const int N = 3e5 + 10;
int ch[N][2],cnt,fail[N],fl[N];
bool vis[N],in[N],flag;
char s[N];
void insert(char s[]){
    int u = 0;
    for(int i = 0;s[i];i ++){
        bool v = s[i] - '0';
        if(!ch[u][v]) ch[u][v] = ++ cnt;
        u = ch[u][v];
    }
    fl[u] = 1;
}

void getfail(){
    queue<int> q;
    for(int i = 0;i < 2;i ++) if(ch[0][i]) q.push(ch[0][i]);
    while(!q.empty()){
        int u = q.front();q.pop();
        for(int i = 0;i < 2;i ++){
            if(ch[u][i]){
                fail[ch[u][i]] = ch[fail[u]][i];
                fl[ch[u][i]] |= fl[fail[ch[u][i]]];
                q.push(ch[u][i]);
            }
            else ch[u][i] = ch[fail[u]][i];
        }
    }
}

void dfs(int u){
    if(in[u]){
        flag = 1;
        return;
    }
    if(vis[u] || fl[u]) return;
    in[u] = vis[u] = 1;
    dfs(ch[u][0]);
    dfs(ch[u][1]);
    in[u] = 0;
}
int n;
int main(){
    scanf("%d",&n);
    for(int i = 0;i < n;i ++){
        scanf("%s",s);
        insert(s);
    }
    getfail();
    flag = 0;
    dfs(0);
    if(flag) puts("TAK");
    else puts("NIE");
    return 0;
}

回文自动机

P5496 【模板】回文自动机(PAM)

题目链接
就是一模板题嘞 封装写起来好舒服
AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 2e6 + 10;

struct PAM_t{
    int ch[26],fail,len,num;
};

struct PAM{
    PAM_t b[N];
    char s[N];
    int cur,n,cnt;
    PAM(){
        b[0].len = 0,b[1].len = -1;
        b[0].fail = 1,b[1].fail = 0;
        cnt = 1;
        cur = 0;
    }
    void read(){
        scanf("%s",s);
    }
    int getfail(int x){
        while(s[n - b[x].len - 1] != s[n] || n - b[x].len - 1 < 0) x = b[x].fail;
        return x;
    }

    void insert(){
        int pre = getfail(cur);
        if(!b[pre].ch[s[n]]){
            b[++ cnt].len = b[pre].len + 2;
            int tmp = getfail(b[pre].fail);
            b[cnt].fail = b[tmp].ch[s[n]];
            b[cnt].num = b[b[cnt].fail].num + 1;
            b[pre].ch[s[n]] = cnt;
        }
        cur = b[pre].ch[s[n]];
    }

    void solve(){
        int k = 0;
        for(n = 0;s[n];n ++){
            s[n] = (s[n] - 97 + k) % 26 + 97;
            s[n] -= 'a';
            insert();
            printf("%d ",b[cur].num);
            k = b[cur].num;
        }
    }
}P;
int main(){
    P.read();
    P.solve();
    return 0;
}

P3649 [APIO2014]回文串

题目链接
也是模板啦 就是要处理一下出现次数而已
和AC自动机的处理方式很像的
记得在外面把短的回文串出现次数加上长串出现次数就行啦(前提是短串是长串的子串,fail指向的不就是最长回文后缀吗,后缀不就是子串了吗)
AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;
const int N = 2e6 + 10;
struct PAM_T{
    int ch[26],fail,len,num;
};

struct PAM{
    PAM_T b[N];
    char s[N];
    int cnt,n,cur;
    PAM(){
        b[0].len = 0,b[1].len = -1;
        b[0].fail = 1,b[1].fail = 0;
        cnt = 1;
        cur = 0;
    }
    void read(){
        scanf("%s",s);
    }
    int getfail(int x){
        while(s[n - b[x].len - 1] != s[n]) x = b[x].fail;
        return x;
    }
    void insert(){
        int pre = getfail(cur);
        if(!b[pre].ch[s[n]]){
            b[++ cnt].len = b[pre].len + 2;
            int tmp = getfail(b[pre].fail);
            b[cnt].fail = b[tmp].ch[s[n]];
            b[pre].ch[s[n]] = cnt;
        }
        cur = b[pre].ch[s[n]];
        b[cur].num ++;
    }
    void solve(){
        for(n = 0;s[n];n ++){
            s[n] -= 'a';
            insert();
        }
        long long ans = 0;
        for(int i = cnt;i;i --){
            b[b[i].fail].num += b[i].num;
            if(b[i].num * 1ll * b[i].len > ans) ans = b[i].num * 1ll * b[i].len;
        }
        printf("%lld\n",ans);
    }
}P;
int main(){
    P.read();
    P.solve();
    return 0;
}

P4287 [SHOI2011]双倍回文

题目链接
需要多维护一个trans数组,用来表示长度小于或等于当前节点长度一半的最长回文后缀 更新方法和fail数组大同小异
新建一个节点后,如果这个节点的长度<=2,那么这个节点的trans直接指向这个节点的fail(因为fail的长度肯定<=1)
否则,就跳fail,判断是否能够扩展以及长度是否满足(和fail更新差不多)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 5e5 + 10;
int ch[N][26],fail[N],len[N],trans[N];
int n,cnt,ans,cur;
char s[N];
int getfail(int x,int i){
    while(s[i - len[x] - 1] != s[i]) x = fail[x];
    return x;
}

void build(){
    for(int i = 0;s[i];i ++){
        int x = s[i] - 'a';
        int p = getfail(cur,i);
        if(!ch[p][x]){
            len[++ cnt] = len[p] + 2;
            fail[cnt] = ch[getfail(fail[p],i)][x];
            ch[p][x] = cnt;
            if(len[cnt] <= 2) trans[cnt] = fail[cnt];
            else{
                int tmp = trans[p];
                while(s[i - 1 - len[tmp]] != s[i] || (len[tmp] + 2) * 2 > len[cnt]) tmp = fail[tmp];
                trans[cnt] = ch[tmp][x];
            }
        }
        cur = ch[p][x];
    }
}
int main(){
    scanf("%d",&n);
    scanf("%s",s);
    fail[0] = 1,fail[1] = 0;
    len[0] = 0,len[1] = -1;
    cur = 0,cnt = 1;
    build();
    for(int i = 2;i <= cnt;i ++){
        if((len[trans[i]] * 2) == len[i] && len[i] % 4 == 0)
            ans = max(ans,len[i]);
    }
    printf("%d\n",ans);
    return 0;
}

以后有机会会写篇回文自动机的博客的(毕竟它比较难)
主要是后缀数组还没学透啊啊啊啊啊好难

资源下载链接为: https://pan.quark.cn/s/5c50e6120579 在Android移动应用开发中,定位功能扮演着极为关键的角色,尤其是在提供导航、本地搜索等服务时,它能够帮助应用获取用户的位置信息。以“baiduGPS.rar”为例,这是一个基于百度地图API实现定位功能的示例项目,旨在展示如何在Android应用中集成百度地图的GPS定位服务。以下是对该技术的详细阐述。 百度地图API简介 百度地图API是由百度提供的一系列开放接口,开发者可以利用这些接口将百度地图的功能集成到自己的应用中,涵盖地图展示、定位、路径规划等多个方面。借助它,开发者能够开发出满足不同业务需求的定制化地图应用。 Android定位方式 Android系统支持多种定位方式,包括GPS(全球定位系统)和网络定位(通过Wi-Fi及移动网络)。开发者可以根据应用的具体需求选择合适的定位方法。在本示例中,主要采用GPS实现高精度定位。 权限声明 在Android应用中使用定位功能前,必须在Manifest.xml文件中声明相关权限。例如,添加<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />,以获取用户的精确位置信息。 百度地图SDK初始化 集成百度地图API时,需要在应用启动时初始化地图SDK。通常在Application类或Activity的onCreate()方法中调用BMapManager.init(),并设置回调监听器以处理初始化结果。 MapView的创建 在布局文件中添加MapView组件,它是地图显示的基础。通过设置其属性(如mapType、zoomLevel等),可以控制地图的显示效果。 定位服务的管理 使用百度地图API的LocationClient类来管理定位服务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值