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

题意:给你一个字符串,并定义两个前缀的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. Python基础之Python语言类型

    编程语言主要从以下几个角度进行分类: 编译型和解释型 静态语言和动态语言 强类型定义语言和弱类型定义语言 编译和解释的区别是什么? 编译器把源程序的每一条语句都编译成机器语言,并保存成二进制文件,这样 ...

  2. [心得]暑假DAY1 | 7-7考试总结

    呼.. 正式开始暑假集训. 今天一上午还在搞7-7的考试改题 然而,该来该去,TLE48过不去了 不知道哪的问题,loj上1w3ms(卡常都没能救得了) 至于T1和T3,简单总结一下算了 排序 感觉很 ...

  3. TCP被动打开 之 第一次握手-接收SYN

    假定客户端执行主动打开,服务器执行被动打开,客户端发送syn包到服务器,服务器接收该包,进行建立连接请求的相关处理,即第一次握手:本文主要分析第一次握手中被动打开端的处理流程,主动打开端的处理请查阅本 ...

  4. PHP7 的部分新特性

    1. 运算符(NULL 合并运算符) $a = $_GET['a'] ?? 1; 它相当于: <php$a = isset($_GET['a']) ? $_GET['a'] : 1; 我们知道三 ...

  5. Error:java: 错误: 不支持发行版本 5

    本文链接:https://blog.csdn.net/wo541075754/article/details/70154604 在Intellij idea中新建了一个Maven项目,运行时报错如下: ...

  6. 黑马vue---13、事件修饰符的介绍

    黑马vue---13.事件修饰符的介绍 一.总结 一句话总结: .stop 阻止冒泡:input type="button" value="戳他" @click ...

  7. 浅析java中的四种线程池

      1.使用线程池的好处 2.JUC中几种常用的线程池 java.util.concurrent包下的Executors工厂类,提供了一系列的线程池的创建方法,其构造方法如下: public Thre ...

  8. oracle中删除某个用户下的所有表

    一般的方法:先使用sql查询: SELECT 'DELETE FROM '|| table_name || ';' FROM USER_TABLES ORDER BY TABLE_NAME; 将查询结 ...

  9. [转]zookeeper入门

    zookeeper的目标是将复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用. 参考文章:http://developer.51cto.com ...

  10. LC 966. Vowel Spellchecker

    Given a wordlist, we want to implement a spellchecker that converts a query word into a correct word ...