IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 回文自动机+CodeTON Round 2 CD -> 正文阅读

[C++知识库]回文自动机+CodeTON Round 2 CD

今天打了一场没啥意思的牛客,只有一个知识点需要注意一下。
回文自动机
回文自动机是一种类似于字典树和ac自动机的数据结构,能够在O(n)级别求解出:以某个字符为结尾的本质不同回文串个数,以某个字符为结尾的最长回文串长度,以某个字符为结尾的回文串出现的次数等等。
等到有时间专门写个PAM专题吧
首先是模板题,结合代码讲一下每个变量代表的意义。
P5496 【模板】回文自动机(PAM)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 5e5+100;
char s[N];
int len[N],n,num[N],fail[N],last,cur,pos,trie[N][26],tot=1;
int getfail(int x,int i)
{
	while(i-len[x]-1<0||s[i-len[x]-1]!=s[i])x=fail[x];
	return x;
}
void pam()
{
    fail[0]=1;
    len[1]=-1;
    for(int i=0;i<n;i++)
    {
        if(s[i]>=1)
            s[i]=(s[i]+last-97)%26+97;
    	pos=getfail(cur,i);
        if(!trie[pos][s[i]-'a'])
        {
        	fail[++tot]=trie[getfail(fail[pos],i)][s[i]-'a'];
        	trie[pos][s[i]-'a']=tot;
        	len[tot]=len[pos]+2;
            num[tot]=num[fail[tot]]+1;
		}
        cur=trie[pos][s[i]-'a'];
        last=num[cur];
        cout<<last<<" ";
	}
}
int main()
{
	cin>>s;
	n=strlen(s);
    pam();
	return 0;
}

len[i]:树中i节点代表的回文串的长度。值得注意的是,我们对于回文串分长度的奇偶情况,所以len[1]代表奇数长度的子树,len[0]代表偶数长度的子树。
num[i]:节点i为结尾的回文串有多少个
fail[i]:节点i失配后指向的节点满足:以此节点为结尾的回文串是节点i的最长回文后缀。

P3649 [APIO2014] 回文串

看一看这个。
根据板子只有一个点:统计每个回文子串出现了几次。

比如www这个串中ww回文串就出现了两次

#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long
using namespace std;
const int N = 5e5+100;
char s[N];
int len[N],n,num[N],fail[N],last,pos,trie[N][26],tot=1;
int cnt[N];
int getfail(int x,int i)
{
	while(i-len[x]-1<0||s[i-len[x]-1]!=s[i])//我们跳到这样一个回文串
        x=fail[x];
	return x;
}
void pam()
{
    fail[0]=1;
    len[1]=-1;
    for(int i=0;i<=n-1;i++)
    {
    	pos=getfail(last,i);
        if(!trie[pos][s[i]-'a'])
        {
        	fail[++tot]=trie[getfail(fail[pos],i)][s[i]-'a'];
        	trie[pos][s[i]-'a']=tot;
        	len[tot]=len[pos]+2;
            num[tot]=num[fail[tot]]+1;
		}
        last=trie[pos][s[i]-'a'];
        cnt[last]++;
	}
}
signed main()
{
	cin>>s;
	n=strlen(s);
    pam();
    int ans=0;
    for(int i=tot;i>=1;i--)
    {
        cnt[fail[i]]+=cnt[i];
        ans=max(ans,cnt[i]*len[i]);
    }
    cout<<ans<<endl;
	return 0;
}

CodeTON Round 2
这俩题都挺直白的。

C. Virus
题意:给你n个马围一圈,一开始n个马有m个感染了病毒,每天病毒马都传染相邻的马,当然如果1 2 3这三匹马3感染病毒,2位置没有马,1位置有马,1和3不算相邻,所以1就不会被传染。
现在农夫每天可以在病毒传播之前牵走一批马隔离,问最少有多少匹马被感染。

思路:m匹马把环分割成m个区间,以一个n=10,m=2,初始感染的马是9 3为例,一个区间有3匹马,另一个有5匹,模拟一下就出做法了

#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int N = 1e5+100;

int a[N];
int b[N];
bool cmp(const int &a,const int &b)
{
    return a>b;
}
signed main()
{
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    for(cin>>t;t;t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            cin>>a[i];
        }
        sort(a+1,a+m+1);
        b[1]=a[1]-1+n-a[m];
        for(int i=2;i<=m;i++)
        {
            b[i]=a[i]-a[i-1]-1;
        }
        sort(b+1,b+m+1,cmp);
        int cnt=0;
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            if(b[i]-cnt>=2)
                ans+=b[i]-cnt-1;
            else if(b[i]-cnt==1)
                ans++;
            else
                break;
            cnt+=4;
        }
        cout<<n-ans<<endl;
    }
    return 0;
}

D. Magical Array
题意:给定n个长度为m的数组,这些数组初始完全一样,经过了k次变化后有一个特殊数组与众不同。
变化:
普通数组:选定一对(i,j),i<j ,让a[i],a[j]减少1,a[i - 1],a[j + 1]增加1
特殊数组:选定一对(i,j),i<j ,让a[i],a[j]减少1,a[i - 1],a[j + 2]增加1

思路:从前缀和角度去分析,发现普通数组的前缀和的和不会发生变化,而特殊数组由于空了一个所以前缀和的和每进行一次操作就-1。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+100;
int pre[N];
signed main()
{
    int t;
    for(cin>>t;t;t--)
    {
        int n,m,maxx=-1,pos=0;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            int sum=0;
            for(int j=1,temp;j<=m;j++)
            {
                cin>>temp;
                sum+=temp;
                pre[i]+=sum;
            }
            maxx=max(maxx,pre[i]);
        }
        for(int i=1;i<=n;i++)
        {
            if(maxx!=pre[i])
            {
                pos=i;
                break;
            }
        }
        cout<<pos<<" "<<maxx-pre[pos]<<endl;
        for(int i=1;i<=n;i++)
            pre[i]=0;
    }
    return 0;
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:25:04  更:2022-08-06 10:27:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:30:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码