sutoringu

题意:

  询问有多少一个字符串内有多少个个子区间,满足可以分成k个相同的串。

分析:

  首先可以枚举一个长度len,表示分成的k个长为len的串。然后从1开始,每len的长度分成一块,分成(n-1)/k+1块,首先可以求出连续的k块的是否是合法。

  此时只求了起点是1+len*i的串,还有些起点在块内的没有求。

  枚举k-1个相同的块,设这些块为i...j,j-i+1=k。然后与求一下第i块和第i-1块最长后缀,设为a,求一下第j块和第j+1块的最长前缀,设为b。说明如果起点在第i-1块的串,必须是后面a个字符,这些串的终点必须是第j+1块的前b个字符。于是计算一下。

  如何求连续的k块是否是一样的?可以求出这连续k块在的rank,然后取一个最大的rank和一个最小的rank,然后求之间的height最小值即可。

  复杂度$nlog^2n$。

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<bitset>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
char s[N];
int t1[N], t2[N], c[N], sa[N], rnk[N], ht[N], f[N][], Log[N];
void getsa(int n) {
int m = , i, *x = t1, *y = t2;
for (i = ; i <= m; ++i) c[i] = ;
for (i = ; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
for (i = ; i <= m; ++i) c[i] += c[i - ];
for (i = n; i >= ; --i) sa[c[x[i]]--] = i;
for (int k = ; k <= n; k <<= ) {
int p = ;
for (i = n - k + ; i <= n; ++i) y[++p] = i;
for (i = ; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
for (i = ; i <= m; ++i) c[i] = ;
for (i = ; i <= n; ++i) c[x[y[i]]] ++;
for (i = ; i <= m; ++i) c[i] += c[i - ];
for (i = n; i >= ; --i) sa[c[x[y[i]]]--] = y[i];
swap(x, y);
p = ;
x[sa[]] = ;
for (i = ; i <= n; ++i)
x[sa[i]] = (y[sa[i]] == y[sa[i - ]] && y[sa[i] + k] == y[sa[i - ] + k]) ? p - : p ++;
if (p > n) break;
m = p;
}
for (i = ; i <= n; ++i) rnk[sa[i]] = i;
ht[] = ;
int k = ;
for (i = ; i <= n; ++i) {
if (rnk[i] == ) continue;
if (k) k --;
int j = sa[rnk[i] - ];
while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
ht[rnk[i]] = k;
}
for (i = ; i <= n; ++i) f[i][] = ht[i];
for (i = ; i <= n; ++i) Log[i] = Log[i >> ] + ;
for (int j = ; j <= Log[n]; ++j)
for (i = ; i + ( << j) - <= n; ++i)
f[i][j] = min(f[i][j - ], f[i + ( << (j - ))][j - ]);
}
int LCP(int i,int j) {
i = rnk[i], j = rnk[j];
if (i > j) swap(i, j);
i ++;
int k = Log[j - i + ];
return min(f[i][k], f[j - ( << k) + ][k]);
}
int LCP2(int i,int j) {
i ++;
int k = Log[j - i + ];
return min(f[i][k], f[j - ( << k) + ][k]);
} set<int> sk;
int n, k, rev[N]; bool check(int len) {
int l = *sk.begin();
set<int>::iterator it = sk.end(); it --;
int r = *it;
return LCP2(l, r) >= len;
}
int check2(int i,int j,int len) {
if (sk.size() >= && !check(len)) return ;
int a = min(len - , LCP(rev[i - ], rev[i - + len]));
if (j + len > n) return ;
int b = min(len - , LCP(j, j + len));
return max(, b - (len - a) + );
}
int main() {
freopen("sutoringu.in", "r", stdin);
freopen("sutoringu.out", "w", stdout);
n = read(), k = read();
scanf("%s", s + );
s[n + ] = '#';
for (int i = ; i <= n; ++i)
s[i + n + ] = s[n - i + ], rev[n - i + ] = i + n + ;
getsa(n + n + );
LL ans = ;
for (int len = ; len <= n; ++len) {
sk.clear();
for (int i = ; i <= n; i += len) {
sk.insert(rnk[i]);
if (sk.size() > k) sk.erase(rnk[i - len * k]);
if (sk.size() == k) ans += check(len);
}
if (len == ) continue;
sk.clear();
for (int i = len + ; i <= n; i += len) {
sk.insert(rnk[i]);
if (sk.size() > k - ) sk.erase(rnk[i - len * (k - )]);
if (sk.size() == k - ) ans += check2(i - (k - ) * len, i, len);
}
}
cout << ans;
return ;
}

模拟赛 sutoringu的更多相关文章

  1. 3.27模拟赛 sutoringu(后缀数组)

    \(\color{white}{mjt是机房模拟赛独自切过题的唯一的人...}\) (应本人要求删掉惹) \(Description\) 给你\(n,k\)和长为\(n\)的字符串\(s\).一个区间 ...

  2. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  3. NOI模拟赛 Day1

    [考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...

  4. NOIP第7场模拟赛题解

    NOIP模拟赛第7场题解: 题解见:http://www.cqoi.net:2012/JudgeOnline/problemset.php?page=13 题号为2221-2224. 1.car 边界 ...

  5. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  6. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  7. 小奇模拟赛9.13 by hzwer

    2015年9月13日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿(explo) [题目背景] 小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞 ...

  8. PKUSC 模拟赛 day1 下午总结

    下午到了机房之后又困又饿,还要被强行摁着看英文题,简直差评 第一题是NOIP模拟赛的原题,随便模拟就好啦 本人模拟功力太渣不小心打错了个变量,居然调了40多分钟QAQ #include<cstd ...

  9. [GRYZ]寒假模拟赛

    写在前面 这是首次广饶一中的OIERS自编自导,自出自做(zuo)的模拟赛. 鉴于水平气压比较低,机(wei)智(suo)的WMY/XYD/HYXZC就上网FQ下海找了不少水(fei)题,经过他们优( ...

随机推荐

  1. CentOS 7下安装Python3.5

    CentOS 7下安装Python3.5 •安装python3.5可能使用的依赖 yum install openssl-devel bzip2-devel expat-devel gdbm-deve ...

  2. Forbidden Attack:7万台web服务器陷入被攻击的险境

    一些受VISA HTTPS保护的站点,因为存在漏洞容易受到Forbidden攻击,有将近70,000台服务器处于危险之中. 一种被称为"Forbidden攻击"的新攻击技术揭露许多 ...

  3. CSS揭秘(一)引言

    借了一本CSS揭秘,国外的一本书,应该是目前相关书目里最好的了,内容非常扎实,不得不说图灵教育出的书真的不错,不然不是很厚的一本书卖到99也是.... 国外的这类书总是以问题开始,然后通过解决问题引出 ...

  4. 从 Azure 下载 Windows VHD

    本文介绍如何使用 Azure 门户从 Azure 下载 Windows 虚拟硬盘 (VHD) 文件. Azure 中的虚拟机 (VM) 将磁盘用作存储操作系统.应用程序和数据的位置. 所有 Azure ...

  5. Azure 托管镜像和非托管镜像对比

    目前中国区 Azure 也已经可以使用命令制作托管镜像了.但对于托管镜像和非托管镜像,就像托管磁盘和非托管磁盘一样,很多人可能一开始无法理解.这里就此进行了一个简单对比: 通过对比测试,这里总结了这两 ...

  6. Java重要类详解之ArrayList类

    https://blog.csdn.net/shengmingqijiquan/article/details/52634640 一.ArrayList概述 ArrayList 是一个数组队列,相当于 ...

  7. Linux 出现 E325:ATTENTION swap

    当用vim打开一个文件的时候,系统提示:E325:ATTENTION Found a swap by the name ".a.swp" owned by:…… …… 这是由于在编 ...

  8. redis之禁用保护模式以及修改监听IP

    今天在安装filebeat的时候,出现了关于redis报错的问题,所以来总结一下: 报错信息是: (error) DENIED Redis is running in protected mode b ...

  9. HTML5 学习总结(三)——本地存储(localStorage、sessionStorage、WebSqlDataBase、IndexedDB)

    HTML5问世以后,前端加入了一个重要的功能,便是本地存储,本地存储可分为4类: Local Storage:总的存储量有所限制,并不能提供真正的检索API,数据的生命期比窗口或浏览器的生命期长,数据 ...

  10. Resharper安装使用手册

    今天在博客园上看到一位大牛写了一遍关于.NET代码优化的文章,其中提到了Resharper这个工具,以前没使用过这个工具,突然想用这个工具来检查一下自己之前代码的规范程度,也是为了写出更规范的代码. ...