神奇的思路,还是要学习一个。

题意:给你一个字符串,并定义两个前缀的lcs、两个后缀的lcp,求式子膜\(2^{64}\)的值。

\[\sum_{1\le i<j\le n} lcp(i,j)lcs(i,j)[lcp(i,j)\le k1][lcs(i,j)\le k2]
\]

分析:

对于一对存在贡献的\(<i,j>\),咱将它们的lcs、lcp拼起来,可知

\[s[i-lcs(i,j)+1,i+lcp(i,j)-1]=s[j-lcs(i,j)+1,j+lcp(i,j)-1]\\
s[i-lcs(i,j)]\not=s[j-lcs(i,j)]\\
s[i+lcp(i,j)]\not=s[j+lcp(i,j)]\\
\]

这启发我们找出所有满足下列条件的子串对\(<i,j,len>\)

\[s[i,i+len-1]=s[j,j+len-1],s[i-1]\not=s[j-1],s[i+len]\not=s[j+len]
\]

可以知道它的贡献为

\[\sum_{\max(1,len-k2+1)}^{\min(len,k1)} k(len-k+1)=\sum_{k=1}^{min(len,k1)}k(len-k+1)-\sum_{k=1}^{\max(0,len-k2)}k(len-k+1)
\]

于是考虑建立SA,并记录后缀的前一个字符。

在height数组上从高到低启发式合并,一边统计答案。

#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std; const int N=1e5+10; int n,k1,k2;
char s[N];
int sa[N],ht[N],rc[N],c[N];
int lp[N],rp[N],bl[N],siz[N],cnt[N][26]; void buildSa() {
int *x=ht,*y=rc,i,p,k,m=128;
for(i=0; i<=m; ++i) c[i]=0;
for(i=1; i<=n; ++i) c[x[i]=s[i]]++;
for(i=1; i<=m; ++i) c[i]+=c[i-1];
for(i=n; i>=1; --i) sa[c[x[i]]--]=i;
for(k=1; k<n; k<<=1) {
for(i=n-k+1,p=0; i<=n; ++i) y[++p]=i;
for(i=1; i<=n; ++i) if(sa[i]>k) y[++p]=sa[i]-k;
for(i=0; i<=m; ++i) c[i]=0;
for(i=1; i<=n; ++i) c[x[y[i]]]++;
for(i=1; i<=m; ++i) c[i]+=c[i-1];
for(i=n; i>=1; --i) sa[c[x[y[i]]]--]=y[i];
swap(x,y), x[sa[1]]=p=1;
for(i=2; i<=n; ++i) x[sa[i]]=
y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
if((m=p)>=n) break;
}
for(i=1; i<=n; ++i) rc[sa[i]]=i;
for(i=1,k=0; i<=n; ++i) {
p=sa[rc[i]-1]; if(k) k--;
while(s[i+k]==s[p+k]) ++k;
ht[rc[i]]=k;
}
// for(int i=1; i<=n; ++i) {
// cout<<(s+sa[i]);
// if(i>1) cout<<" "<<ht[i];
// cout<<endl;
// }
} pair<int,int> h[N];
ull sm(int x) {return (ull)x*(x+1)/2;}
ull ssm(int x) {return (ull)x*(2*x+1)*(x+1)/6;}
ull F(int x) {
if(x>=k1+k2) return 0;
ull s1=(ull)(x+1)*sm(min(x,k1))-ssm(min(x,k1));
ull s2=(ull)(x+1)*sm(max(0,x-k2))-ssm(max(0,x-k2));
return s1-s2;
}
ull f[N];
ull calc(int x,int y) {
ull res=(ull)siz[x]*siz[y];
for(int i=0; i<26; ++i) res-=(ull)cnt[x][i]*cnt[y][i];
return res;
}
void merge(int x,int y) {
for(int i=0; i<26; ++i) cnt[y][i]+=cnt[x][i];
for(int i=lp[x]; i<=rp[x]; ++i) bl[i]=y;
lp[y]=min(lp[y],lp[x]);
rp[y]=max(rp[y],rp[x]);
siz[y]+=siz[x];
} int main() {
scanf("%s%d%d",s+1,&k1,&k2);
n=strlen(s+1);
k1=min(k1,n);
k2=min(k2,n);
for(int i=1; i<=n; ++i) f[i]=F(i);
buildSa();
for(int i=1; i<=n; ++i) {
lp[i]=rp[i]=bl[i]=i; siz[i]=1;
if(sa[i]>1) cnt[i][s[sa[i]-1]-'a']++;
}
for(int i=2; i<=n; ++i)
h[i-1]=make_pair(-ht[i],i);
sort(h+1,h+n);
ull ans=0;
for(int i=1; i<n; ++i) {
int len=-h[i].first;
int x=bl[h[i].second];
int y=bl[h[i].second-1];
if(siz[x]>siz[y]) swap(x,y);
ans+=(ull)f[len]*calc(x,y);
merge(x,y);
// printf("%d,%d,%d,(%llu)\n",len,x,y,ans);
}
printf("%llu\n",ans);
return 0;
}

[LGP5115] Check,Check,Check one two!的更多相关文章

  1. 烟大 Contest1024 - 《挑战编程》第一章:入门 Problem G: Check The Check(模拟国际象棋)

    Problem G: Check The Check Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 10  Solved: 3[Submit][Statu ...

  2. uva 10196 Check The Check

    题目:10196 - Check The Check 思路:水题..模拟 这个代码,前半部分是在数统机房上课的时候写的,挫了点,懒得改了. #include <cstdio> #inclu ...

  3. UVA - 10196:Check The Check

    类型:简单模拟 大致题意:已知国际象棋行棋规则,给你一个局面,问是否将军?谁将谁的军?(保证不会同时将军) 思路:都以小写字母 测试 是否将 大写字母. 然后一个局面测两次(一次直接测,一次反转棋盘, ...

  4. SQL PRIMARY KEY 约束\SQL FOREIGN KEY 约束\SQL CHECK 约束

    SQL PRIMARY KEY 约束 PRIMARY KEY 约束唯一标识数据库表中的每条记录. 主键必须包含唯一的值. 主键列不能包含 NULL 值. 每个表都应该有一个主键,并且每个表只能有一个主 ...

  5. check约束条件

    --约束:对列的值起一个约束性的作用,规定列的值的范围 --主键.外键.非空.自增长标识列.唯一列(unique).check约束 --check 约束 --在某个表里点击右键→设计→进去找到要约束的 ...

  6. Health Check in eShop -- 解析微软微服务架构Demo(五)

    引言 What is the Health Check Health Check(健康状态检查)不仅是对自己应用程序内部检测各个项目之间的健康状态(各项目的运行情况.项目之间的连接情况等),还包括了应 ...

  7. SQLServer之修改CHECK约束

    使用SSMS数据库管理工具修改CHECK约束 1.打开数据库,选择数据表->右键点击->选择设计(或者展开约束,选择约束,右键点击,选择修改,后面步骤相同). 2.选择要修改的数据列-&g ...

  8. SQL CHECK 约束

    SQL CHECK 约束 CHECK 约束用于限制列中的值的范围. 如果对单个列定义 CHECK 约束,那么该列只允许特定的值. 如果对一个表定义 CHECK 约束,那么此约束会在特定的列中对值进行限 ...

  9. 约束4:唯一约束,Check约束和null

    大家知道,关系型数据库的逻辑运算的结果是三值型的,TRUE,FALSE和UNKNOWN,特别是,NULL值和任何值都不相等,任何值和NULL的比较,返回的逻辑结果都是unknown.而NULL值在唯一 ...

  10. The Singapore NRIC Check Digit

    The Singapore NRIC number is made up of 7 digits and a letter behind. This letter is calculated from ...

随机推荐

  1. zabbix服务端接收的数据类型,便于编写脚本向服务端提交数据

    1.数据类型1:zabbix_agent执行脚本提交字典 UserParameter=tcp_port_listen,/usr/local/zabbix/share/script/get_game_p ...

  2. pymysql pymysql.err.OperationalError 1045 Access denied最简单解决办法

    我使用的是python3.6+pymysql+mysql8.0 在cmd命令行直接输入mysql回车出现:ERROR 1045 (28000): Access denied for user 'ODB ...

  3. vue的通信方式(二)---祖父孙三个级别的之间的隔代通信

    在之前的文章中我们提到了vue常用的几种通信方式,如父子,子父,以及兄弟组件之间的通信,可以通过这个传送门了解他们:Vue通信方式(一) 当我们如果遇到祖组件,父组件,孙组件,三个级别嵌套时,我们该怎 ...

  4. C++入门经典-例7.8-const对象,标准尺寸

    1:当建立一个对象之后,如果不希望它的任何数据发生改变,可以将其直接声明为const对象,例如: const 类名 对象名 const对象必须初始化.我们可以调用它的数据和函数,但是不可以对他们进行修 ...

  5. node版本如何升级

    爬坑后的结论:window系统升级node只能到node官网下载window安装包来覆盖之前的node. 以下为我的爬坑之路: 今天安装了vue cli 3,使用命令时报: You are using ...

  6. R语言:读入txt文件中文文本出现乱码解决方案

    下载安装 readr 因为使用内置函数 read.table() 读入应该是格式不符合要求会报错 library(readr) help(package="readr") 可以使用 ...

  7. python:科学计数法转化为浮点型数据

    def as_num(x): y='{:.5f}'.format(x) # 5f表示保留5位小数点的float型 return(y) 实验一下 as_num(1.2e-4) In [3]:as_num ...

  8. java 获取本地 mac 地址

    主要参考:Java获取本机MAC地址/IP地址/主机名 做的更改: 1.我的windows是中文版,程序中获取mac时是按照physical address 获取的,添加上"物理地址&quo ...

  9. Android应用开发编译框架流程与IDE及Gradle概要

    1 背景 建议阅读本文之前先阅读<Android Studio入门到精通>和<Groovy脚本基础全攻略>及<Gradle脚本基础全攻略>三篇博客作为背景知识,这样 ...

  10. 装机、做系统必备:秒懂MBR和GPT分区表____转载网络

    装机.做系统必备:秒懂MBR和GPT分区表 科技美学 2016-10-17 16:36:23 阅读(3835) 评论(4) 很多网友询问MBR和GPT的问题,涉及到硬盘操作系统的安装,其实除了MBR和 ...