题解-ARC077F
时间:2021-08-05
本文章向大家介绍题解-ARC077F,主要包括题解-ARC077F使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
神仙字符串结论题。
我们先进行一次操作变成一个 \(SS\) 串,然后考虑 \(S\) 的循环节 \(G\)。
- \(G\) 是 \(S\) 的整循环节
那么这个串会变成 \(SGSG\),\(SGGSGG\),...,\(SGGGG...SGGGG....\),由于是无限长我们只需考虑前半部分即可。这个直接求就行。
- \(G\) 不是 \(S\) 的整循环节
其实只是上一部分的扩展。
还是只用考虑前半部分,而前半部分的情况是 \(S_i=S_{i-1}+S_{i-2}\),也就是 \(S\),\(SG\),\(SGS\),\(SGSSG\)(其实样例已经给了提示)。
接下来我们来证明:
该结论等价于证明 \(SG\) 的最小循环节为 \(S\),且不会出现 \(G\) 变成整循环节的情况。设 \(SG=T\)
我们假设存在一个循环节 \(p\) 比 \(S\) 更短,那么 \(p\) 也是 \(S\) 的循环节,所以 \(T[i]=T[i-p]\) 由于 \(G\) 是 \(S\) 的前缀,所以 \(T[i]=T[i-|S|]\),又因为 \(G\) 是周期,所以 \(i-p\equiv i-|S|\pmod |G|\),\(|p|\equiv |S|\pmod |G|\),由于弱周期引理,\(S\) 有新的周期 \(\gcd(|p|,|G|)\),所以 \(p\) 是 \(|G|\) 的倍数,所以 \(|S|\bmod |G|=0\) 矛盾!
于是我们直接暴力模拟即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2000005;
template <typename T>
void read(T &x) {
T flag = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag = -1;
for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
x *= flag;
}
char s[maxn];
int nxt[maxn];
ll l, r;
int n, m;
ll cnt[30], cntg[30], ans[30];
ll f[maxn];
ll cur[30], lst[30];
void solve(ll x, ll v) {
if (x == 0) return;
if (x <= n) {
for (int i = 1; i <= x; i++) ans[s[i] - 'a'] += v;
} else {
x -= n;
for (int i = 0; i < 26; i++) ans[i] = ans[i] + v * (cnt[i] + cntg[i] * (x / m));
for (int i = 1; i <= x % m; i++) ans[s[i] - 'a'] += v;
}
}
void dfs(ll x, ll v) {
if (x <= 0) return;
if (x <= n) {
for (int i = 1; i <= x; i++) ans[s[i] - 'a'] += v;
return;
}
f[1] = n, f[2] = n + m;
int now = 2;
for (int i = 0; i < 26; i++) cur[i] = cnt[i] + cntg[i], lst[i] = cnt[i];
while (f[now] <= x) {
if (now > 2) {
for (int i = 0; i < 26; i++) {
ll tmp = cur[i];
cur[i] += lst[i];
lst[i] = tmp;
}
}
f[now + 1] = f[now] + f[now - 1];
now++;
}
if (now == 2) {
for (int i = 0; i < 26; i++) ans[i] += lst[i] * v;
dfs(x - f[now - 1], v);
} else {
for (int i = 0; i < 26; i++) ans[i] += cur[i] * v;
dfs(x - f[now - 1], v);
}
}
int main() {
scanf("%s", s + 1);
read(l); read(r);
n = strlen(s + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j && s[j + 1] != s[i]) j = nxt[j];
if (s[j + 1] == s[i]) j++;
nxt[i] = j;
}
int tmp = nxt[n];
while (tmp >= (n + 1) / 2) {
tmp = nxt[tmp];
}
n -= tmp;
for (int i = 1; i <= n; i++) cnt[s[i] - 'a']++;
m = n - nxt[n];
for (int i = 1; i <= m; i++) cntg[s[i] - 'a']++;
if (n % (n - nxt[n]) == 0) {
solve(r, 1); solve(l - 1, -1);
for (int i = 0; i < 26; i++) printf("%lld ", ans[i]);
} else {
dfs(r, 1); dfs(l - 1, -1);
for (int i = 0; i < 26; i++) printf("%lld ", ans[i]);
}
return 0;
}
原文地址:https://www.cnblogs.com/zcr-blog/p/15106469.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 浅析php怎么实现爬取数据原理
- 在 Laravel 中动态隐藏 API 字段的方法
- php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
- Thinkphp 5.0实现微信企业付款到零钱
- 实现php删除链表中重复的结点
- YII分模块加载路由的实现办法
- ThinkPHP5.0框架实现切换数据库的方法分析
- php微信公众号开发之微信企业付款给个人
- tp5框架的增删改查操作示例
- PHP使用函数用法详解
- 微信企业转账之入口类分装php代码
- 多个Laravel项目怎么共用migrations详解
- layui数据表格自定义每页条数limit设置
- Laravel 集成微信用户登录和绑定的实现
- PHP实现微信对账单处理