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. 常用内置方法之:__str__,__repr__

    class Test(object): def __init__(self): pass def __str__(self): return "test" test = Test( ...

  2. MySQL大数据表水平分区优化的详细步骤

    将运行中的大表修改为分区表 本文章代码仅限于以数据时间按月水平分区,其他需求可自行修改代码实现 1. 创建一张分区表 这张表的表字段和原表的字段一摸一样,附带分区 1 2 3 4 5 6 7 8 9 ...

  3. 将TXT文件 导入 sqlserver数据库

    情景一:​ 数据库已存在旧表名 old_table,列名old_column_name. 将TXT文件导入数据库已存在旧表old_table中,导入过程中需注意 数据源中列名可全部不修改 或 全部修改 ...

  4. 【待补充】[Python_1] Python 安装

    0. 说明 安装教程网上有很多,等下次安装再补充笔记 Python 下载地址

  5. 【转】Linxu学习---top实践

    [原文]https://www.toutiao.com/i6591053058258502147/ 在实际开发中,有时候会收到一些服务的监控报警,比如CPU飙高,内存飙高等,这个时候,我们会登录到服务 ...

  6. Linux搭建kafka

    一.安装Java 1.查看linux 的系统版本 root@aliyun:~# uname --m x86_64 2.安装java mkdir -p /usr/local/java tar -xf j ...

  7. 乘风破浪:LeetCode真题_031_Next Permutation

    乘风破浪:LeetCode真题_031_Next Permutation 一.前言 这是一道经典的题目,我们实在想不出最好的方法,只能按照已有的方法来解决,同时我们也应该思考一下为什么要这样做?是怎么 ...

  8. .netcore部署Linux并结合Nginx反向代理 get started

    一..NetCore网站准备与发布 首先准备好一个ASP.NET Core Web应用程序,我这里就使用新建的示例站点作为demo演示,使用dotnet publish 命令发布网站. 或者使用VS的 ...

  9. 舌尖上的javascript数组和字符串基本操作

    Javascript数组基本操作 Javascript中的数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性,索引可能是整数,然而这些数字索引在内部被转换为字符串类型,这是因为javascrip ...

  10. DB-Engines Ranking

    DB-Engines Ranking trend chart The DB-Engines Ranking ranks database management systems according to ...