题面

题解

$ \because \sum_{1 \leq i < j \leq n} i + j = \frac{n(n-1)(n+1)}2 $

所以只需求$\sum lcp(i,j)$即可。

$ \because lcp(i,j)=\min_{rank[i] \leq k \leq rank[j]}\{height[k]\} $

所以可以选用最小值分治算法:

int min[maxn];
long long ans;
void Div(int l, int r)
{
if(l == r) return (void)(ans += height[l]);
int mid = (l + r) >> 1;
Div(l, mid); Div(mid + 1, r);
min[mid] = height[mid];
min[mid + 1] = height[mid + 1];
for(RG int i = mid - 1; i >= l; i--)
min[i] = std::min(min[i + 1], height[i]);
for(RG int i = mid + 2; i <= r; i++)
min[i] = std::min(min[i - 1], height[i]);
int j = mid;
for(RG int i = mid; i >= l; i--)
{
while(j < r && min[j + 1] >= min[i]) ++j;
ans += 1ll * min[i] * (j - mid);
}
j = mid + 1;
for(RG int i = mid + 1; i <= r; i++)
{
while(j > l && min[j - 1] > min[i]) --j;
ans += 1ll * min[i] * (mid + 1 - j);
}
}
//...
Div(1, n);

但是我们要精益求精,我们可以想一想$O(n)$的算法。

用栈维护前面与$i$最近且小于等于$height[i]$的元素$p$

则转移方程为:

$ f[i]=f[p]+(i-p)\times height[i] $

//...
long long f[maxn];
struct node { int val, pos; };
std::stack<node> stk; int main()
{
//...
long long ans = 0; int pos = 0;
for(RG int i = 1; i <= n; i++)
{
int p = pos;
while(!stk.empty() && stk.top().val > height[i]) stk.pop();
if(!stk.empty()) p = stk.top().pos;
ans += (f[i] = f[p] + (i - p) * height[i]);
if(!height[i]) pos = i;
stk.push((node){height[i], i});
}
}

代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<stack>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x)) inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (!isdigit(ch))) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
} const int maxn(500010);
char s[maxn];
int n, sa[maxn], rank[maxn], height[maxn]; void sort(int m)
{
static int t[maxn], t2[maxn], c[maxn];
int i, *x = t, *y = t2, p = 0;
std::fill(c + 1, c + m + 1, 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; i--) sa[c[x[i]]--] = i;
for(RG int k = 1; k <= n && p < n; k <<= 1)
{
p = 0;
for(i = n - k + 1; i <= n; i++) y[++p] = i;
for(i = 1; i <= n; i++) if(sa[i] > k) y[++p] = sa[i] - k;
std::fill(c + 1, c + m + 1, 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; i--) sa[c[x[y[i]]]--] = y[i];
std::swap(x, y), p = 1, x[sa[1]] = 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;
m = p;
}
} void get_height()
{
int k = 0;
for(RG int i = 1; i <= n; i++) rank[sa[i]] = i;
for(RG int i = 1; i <= n; i++)
{
if(k) --k;
int j = sa[rank[i] - 1];
while(s[i + k] == s[j + k]) ++k;
height[rank[i]] = k;
}
} long long f[maxn];
struct node { int val, pos; };
std::stack<node> stk; int main()
{
#ifndef ONLINE_JUDGE
file(cpp);
#endif
scanf("%s", s + 1); n = strlen(s + 1);
sort(130); get_height();
long long ans = 0; int pos = 0;
for(RG int i = 1; i <= n; i++)
{
int p = pos;
while(!stk.empty() && stk.top().val > height[i]) stk.pop();
if(!stk.empty()) p = stk.top().pos;
ans += (f[i] = f[p] + (i - p) * height[i]);
if(!height[i]) pos = i;
stk.push((node){height[i], i});
}
printf("%lld\n", 1ll * n * (n - 1) * (n + 1) / 2 - ans * 2);
return 0;
}

【AHOI2013】差异的更多相关文章

  1. BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2326  Solved: 1054[Submit][Status ...

  2. bzoj 3238 Ahoi2013 差异

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2357  Solved: 1067[Submit][Status ...

  3. BZOJ 3238: [Ahoi2013]差异 [后缀自动机]

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2512  Solved: 1140[Submit][Status ...

  4. BZOJ_3238_[Ahoi2013]差异_后缀自动机

    BZOJ_3238_[Ahoi2013]差异_后缀自动机 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sam ...

  5. BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  6. 【LG4248】[AHOI2013]差异

    [LG4248][AHOI2013]差异 题面 洛谷 题解 后缀数组版做法戳我 我们将原串\(reverse\),根据后缀自动机的性质,两个后缀的\(lcp\)一定是我们在反串后两个前缀的\(lca\ ...

  7. 【BZOJ3238】[AHOI2013]差异

    [BZOJ3238][AHOI2013]差异 题面 给定字符串\(S\),令\(T_i\)表示以它从第\(i\)个字符开始的后缀.求 \[ \sum_{1\leq i<j\leq n}len(T ...

  8. P4248 [AHOI2013]差异 解题报告

    P4248 [AHOI2013]差异 题目描述 给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀.求 \[\displaystyle \s ...

  9. 【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3047  Solved: 1375 Description In ...

  10. bzoj 3238: [Ahoi2013]差异 -- 后缀数组

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 一行,一个字符串S Output 一行,一个 ...

随机推荐

  1. Linux环境编程之IPC进程间通信(五):Posix消息队列1

    对于管道和FIFO来说.必须应该先有读取者存在.否则先有写入者是没有意义的. 而消息队列则不同,它是一个消息链表,有足够写权限的线程可往别的队列中放置消息,有足够读权限的线程可从队列中取走消息.每一个 ...

  2. Calabash(葫芦娃)

    嘟嘟嘟 第一眼就觉得肯定某种是最短路,然后想了半天也不知道.然后就把送的50分写了,然后就爆搜,结果因为一个错误的剪枝竟然90分?!只能怪数据太水…… 考完试后听bin哥讲,说就是普通的最短路,只不过 ...

  3. Jmeter--thrift接口压测,调用jar包失败报错:java.lang.NoSuchMethodError:

    调用thrift接口压测的jar包,出现了错误:java.lang.NoSuchMethodError: 错误可能的原因: 有这个类,该类真的没有这个方法 有这个类,而且有好几个,他们之间发生了冲突 ...

  4. uva 10369 Arctic Network (最小生成树加丁点变形)

    The Department of National Defence(DND)wishestoconnectseveral northern outposts by a wireless networ ...

  5. .NET Core中基类可以反射子类的成员

    我们定义一个类DemoA,再定义一个类DemoB继承DemoA.当构造一个DemoB类对象后,我们可以通过其调用基类DemoA中的方法来反射子类DemoB的成员. 新建一个.NET Core控制台项目 ...

  6. ASP.NET Core 中的 WebSocket 支持(转自MSDN)

    本文介绍 ASP.NET Core 中 WebSocket 的入门方法. WebSocket (RFC 6455) 是一个协议,支持通过 TCP 连接建立持久的双向信道. 它用于从快速实时通信中获益的 ...

  7. EF Core 2.0中如何手动映射数据库的视图为实体

    由于Scaffold-DbContext指令目前还不支持自动映射数据库中的视图为实体,所以当我们想使用EF Core来读取数据库视图数据的时候,我们需要手动去做映射,本文介绍如何在EF Core中手动 ...

  8. DecimalFormat的使用

    DecimalFormat,四舍五入时需要设置RoundingMode 1.占位符0: 比实际数字的位数多,不足的地方用0补上. new DecimalFormat("00.00" ...

  9. 搭建springboot项目

    1.搭建环境windows10+jdk1.8+eclipse4.8+maven 2.为了学习微服务架构学习搭建基础项目 3.分为两种搭建方式为maven项目和单独建立springboot项目(ecli ...

  10. CSP 试题编号201803-1 Java实现

    import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner input ...