首页 > 其他分享 >P9089 「SvR-2」Work 题解

P9089 「SvR-2」Work 题解

时间:2024-02-15 16:33:22浏览次数:33  
标签:cur int 题解 top Work 合法 端点 SvR sta

P9089 「SvR-2」Work

可以找到一些性质:

  1. 如果串 \(c(字符)+A\) 合法则串 \(A\) 合法,反之如果串 \(A\) 不合法则串 \(c(字符)+A\) 不合法
  2. 如果串 \(A,B\) 合法(\(len(A)<len(B)\))且 \(c+A\) 合法,则 \(c+B\) 合法,而长度最小的合法串一定是一个后缀组成的

那么可以得到以下算法
用一个栈维护合法区间的右端点(实际记录的是后缀的哈希值)
从后往前遍历,对于点 &i&,将其视为左端点,如果以栈顶为右端点的串不能被一个后缀表示则退栈(直到栈为空)
此时以 \(i\) 为左端点的合法串的数量即为栈中元素的数量
最后将该点作为右端点加入栈中即可

用 \(set[i]\) 储存长度为 \(i\) 的后缀,即可判断是否能被一个后缀表示
时间复杂度\(O(nlogn)\)

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int N=2000006,M1=1e9+7,M2=1e9+1,D=2011111;

int n,cm1[N+10],cm2[N+10];
string s[N];
char cps[N];

//双哈希 
struct HAS{ int l,x,y; };
//bool operator<(const HAS& a,const HAS& b){ if(a.x^b.x) return a.x<b.x; else return a.y<b.y; }//set用 
HAS operator+(const HAS& a,const char& b){ return (HAS){a.l+1,(a.x*D%M1+b-'a')%M1,(a.y*D%M2+b-'a')%M2}; }//加入一个字符 
HAS operator-(const HAS& a,const HAS& b){ return (HAS){a.l-b.l,(a.x-b.x*cm1[a.l-b.l]%M1+M1)%M1,(a.y-b.y*cm2[a.l-b.l]%M2+M2)%M2}; }//a段减去 后面的 b段 
set<HAS>st[N];
HAS sta[N];
int top=0;

void init(){ cm1[0]=cm2[0]=1; for(int i=1;i<=1e6+10;i++) cm1[i]=cm1[i-1]*D%M1, cm2[i]=cm2[i-1]*D%M2; }
signed main(){
	
	init();
	
	scanf("%lld", &n);
	for(int i=1;i<=n;i++){ scanf("%s", cps); s[i]=cps; }
	
	//倒着插入每个后缀
	for(int i=1;i<=n;i++){
		int len=s[i].length();
		HAS cur=(HAS){0,0,0};
		for(int j=len-1;j>=0;j--){
			cur=cur+s[i][j];
			st[cur.l].insert(cur);
		}
	}
	
	int ans=0;
	for(int i=1;i<=n;i++){
		HAS cur=(HAS){0,0,0};
		sta[top=1]=cur;
		int len=s[i].length();
		for(int j=len-1;j>=0;j--){
			cur=cur+s[i][j];
			while(top&&!st[cur.l-sta[top].l].count(cur-sta[top])) top--;//不满足则退栈 
			ans+=top;//top为 以当前节点为左端点的 有意义的子串数 
			sta[++top]=cur;
		}
	}
	
	printf("%lld\n", ans);
	
	return 0;
} 

标签:cur,int,题解,top,Work,合法,端点,SvR,sta
From: https://www.cnblogs.com/Idtwtei/p/18016331

相关文章

  • 「题解」P6130 随机红包
    在\([0,1]\)上随机撒\((n-1)\)个点划分成\(n\)段,求第\(k\)大的段长的期望。从Appleblue17老师的题解中学的,大概详细写很多一笔带过但是我不认为很简单的步骤。Part1令随机变量\(X\)为第\(k\)大的段长。\(E(X)=\int_0^1P(X=x)x\textdx=\int_0^1P(X\geqx)\text......
  • 「题解」ARC139F Many Xor Optimization Problems
    考虑线性空间的标准基底(即每个主元都只有对应向量有值),答案为所有基底异或和。对于一个秩\(k\)计算它对答案的贡献。固定主元为\(a_1<a_2<\cdots<a_k\),各种情况应该是等概率,也就是对第\(i\)个基底来说,\(a_i\)位一定为\(1\),再往下的位除了在\(a\)出现过的以外的位0/1是......
  • CF1928E题解
    ModularSequence题目传送门题解发现\(a_i+y\)与\(a_i\bmody\)均不改变\(a_i\)模\(y\)的余数,所以答案序列的每个元素均可表示为\(x\bmody+ky\)的形式,先让\(s\)减去\(n\times(x\bmody)\),再除以\(y\),这样原序列可以被划分为一个从\(\lfloor\dfrac{x}{y}\rflo......
  • luogu6600题解
    题意中的字母T可以看作一个回文的\(1\)串和回文串中心带一个向下的\(1\)串。我们先来考虑朴素做法,可以枚举这个中心然后扩展来找有几个符合要求的串。朴素做法显然复杂度不对。沿着朴素的思路优化。如果只考虑\(w\gea\)和\(h\geb\)这两个要求很容易想到容斥。此......
  • 问题解决之-List of devices attached
    背景:计划是通过appium+mumu模拟器进行app测试学习,但是安好appium、mumu12模拟器、AndroidStudio(已进行环境变量配置)后,发现mumu12模拟器无法识别,输入adbdevices回车后,显示如下:通过一系列的资料查找解决过程如下:1、mumu模拟器连接:详见官方解决方法:https://mumu.163.com/help/......
  • AtCoder Beginner Contest 340 题解
    AtCoderBeginnerContest340题解去我的洛谷博客里看这篇文章!A-ArithmeticProgression模拟即可。//2024/2/11PikachuQAQ#include<iostream>usingnamespacestd;inta,b,d;intmain(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>......
  • AtCoder Beginner Contest 340 题解
    AtCoderBeginnerContest340题解去我的洛谷博客里看这篇文章!A-ArithmeticProgression模拟即可。//2024/2/11PikachuQAQ#include<iostream>usingnamespacestd;inta,b,d;intmain(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>......
  • 「JOI Open 2019」三级跳 题解
    https://loj.ac/p/3153Part1暴力暴力思路:每次询问的时候,枚举\(a\)和\(b\)在哪里,然后就确定了\(c\)的范围\([2\timesb-a]\),找这个范围内的最大的A[c]即可。Part2优化舍解考虑哪一些\([a,b]\)是明显不优的。如果存在\(i\),满足\(a<i<b\)且\(A[i]<\min(A[a],A[b......
  • P4113 [HEOI2012] 采花 题解
    题目链接:采花这题数据加强到卡了\(2e6\)的可持久化线段树在线做法,先给只tle了最后一个点的代码:卡常参照代码#include<bits/stdc++.h>//#pragmaGCCoptimize(2)//#pragmaGCCoptimize("Ofast,no-stack-protector,unroll-loops,fast-math")//#pragmaGCCtarget("......
  • 【XV6】 networking
    代码:https://github.com/JasenChao/xv6-labs.gitE1000网络设备驱动题目已经在kernel/e1000.c中给出了E1000的初始化函数和发送接收函数,要求完善发送和接收的功能。其他相关的代码,上层的网络协议在kernel/net.c和kernel/net.h中。PCI总线上搜索网卡的代码在kernel/pci.c中://t......