【做题】NOWCODER142A Ternary String——数列&欧拉定理
题意:你有一个长度为\(n\),且仅由012构成的字符串。每经过一秒,这个字符串所有1后面会插入一个0,所有2后面会插入一个1,然后会删除第一个元素。求这个字符串需要多少秒变为空串,对\(10^9+7\)取模。
\(n \leq 10^5\)
显然这个答案是可以从左往右维护当前已经经过的时间,一位位算过来的。
设当前已经经过了\(n\)秒,那么,容易得到再删除下一个0需要1秒,再删除下一个1需要\(n+2\)秒。然而若下一个元素为2,似乎并不好处理。但至少我们能得到一个\(O(n)\)的算法:
int func1(int n) { // 删除1所需时间
return n + 2;
}
int func2(int n) {
int ret = 0;
for (int k = 0 ; k <= n ; ++ k) // 统计删除这个2所产生的1的时间
ret = ret + func1(ret) + k;
ret = ret + 1; // 删除这个2还要1秒
return ret;
}
于是,我们设数列\({a_n}\)表示\(n\)后删除一个2的时间是\(a_n+1\),那么,我们能得到\(a_n = 2a_{n-1} + n + 2\)。那么,我们就能求出其通项式\(a_n = 6 \times 2^n - n - 4\)。
因此,删除下一个2需要\(6 \times 2^n - n - 3\)秒。
到这里问题还没有解决,因为\(n\)在指数里面。这样,如果我们要求答案对\(10^9+7\)取模的值,就要求答案对\(\phi(10^9+7)\)取模的值。而当模数\(p\)与\(2\)不互质时,可以参考bzoj3884的做法,令\(p=2^k q\),其中\(gcd(2,q)=1\),那么我们有\(2^n \mod p = 2^k (2 ^{n-k} \mod q) = 2^k (2^{n-k \mod \phi(q)})\)。于是我们就可以缩小模数,一直到1。因为所有不等于\(1\)的\(q\)都有\(2 | \phi (q)\),所以除第一个外所有\(p\)都是偶数,则\(\phi(q) \leq q \leq \frac {p} {2}\)。因此我们只要对\(O(\log n)\)个答案求解。
实现时还要考虑\(n < k\)的情况,特判一下就可以了。
时间复杂度\(O(n \log^2 n)\)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100010, MAX = 40000, MOD = (int)(1e9 + 7);
char s[N];
int n,isp[MAX + 10],pri[MAX],pcnt,val[N],nex[N],sta[N],top,rel[N];
int getphi(int x) {
int ret = x;
for (int i = 1 ; pri[i] * pri[i] <= x ; ++ i) {
if (x % pri[i] == 0) {
ret /= pri[i];
ret *= pri[i] - 1;
while (x % pri[i] == 0) x /= pri[i];
}
}
if (x != 1) ret = ret / x * (x-1);
return ret;
}
int power(int a,int b,int mod) {
int ret = 1;
while (b) {
if (b&1) ret = 1ll * ret * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return ret;
}
void prework() {
for (int i = 2 ; i <= MAX ; ++ i) {
if (!isp[i]) pri[++pcnt] = i;
for (int j = 1 ; j <= pcnt && pri[j] * i <= MAX ; ++ j) {
isp[pri[j] * i] = 1;
if (i % pri[j] == 0) break;
}
}
for (int cur = MOD ; ; ) {
sta[++top] = cur;
if (cur == 1) break;
while ((cur&1) == 0) cur >>= 1;
cur = getphi(cur);
}
}
signed main() {
int T;
prework();
scanf("%lld",&T);
while (T --) {
scanf("%s",s+1);
n = strlen(s+1);
for (int i = 0 ; i <= n ; ++ i)
val[i] = 0;
rel[0] = 0;
for (int i = 1 ; i <= n ; ++ i) rel[i] = -1;
for (int i = 1 ; i <= n ; ++ i) {
if (s[i] == '0') rel[i] = rel[i-1] + 1;
if (s[i] == '1') rel[i] = 2 * (rel[i-1] + 1);
if (s[i] == '2') rel[i] = 6 * power(2,rel[i-1],MOD) - 3;
if (rel[i] >= 20) {
rel[i] = -1;
break;
}
}
for (int i = top - 1 ; i >= 1 ; -- i) {
int y = sta[i], x = 1, k = 0;
while ((y&1) == 0) x <<= 1, k ++, y >>= 1;
for (int j = 1 ; j <= n ; ++ j) {
if (s[j] == '0') nex[j] = 1;
else if (s[j] == '1') nex[j] = (nex[j-1] + 2) % sta[i];
else {
if (rel[j-1] != -1) nex[j] = (6 * power(2,rel[j-1],sta[i]) - nex[j-1] - 3) % sta[i];
else nex[j] = ((x * power(2,((val[j-1] - k) % sta[i+1] + sta[i+1]) % sta[i+1],y)) * 6 - nex[j-1] - 3) % sta[i];
}
nex[j] = (nex[j-1] + nex[j]) % sta[i];
}
for (int j = 0 ; j <= n ; ++ j)
val[j] = (nex[j] % sta[i] + sta[i]) % sta[i];
}
printf("%lld\n",val[n]);
}
return 0;
}
小结:本题无非不是两个部分,一是数列求解,二是处理指数。关键还是在于清晰的思路。
【做题】NOWCODER142A Ternary String——数列&欧拉定理的更多相关文章
- 【做题】CF119D. String Transformation——KMP
题意:有两个字符串\(a,b\),下标从\(0\)开始.求数对\((i,j)\)满足\(a[i+1:j] + r(a[j:n]) + r(a[0:i+1]) = b\),其中\(r(s)\)表示字符串 ...
- 2018牛客网暑期ACM多校训练营(第四场) A - Ternary String - [欧拉降幂公式][扩展欧拉定理]
题目链接:https://www.nowcoder.com/acm/contest/142/A 题目描述 A ternary string is a sequence of digits, where ...
- codeforces ~ 1009 B Minimum Ternary String(超级恶心的思维题
http://codeforces.com/problemset/problem/1009/B B. Minimum Ternary String time limit per test 1 seco ...
- 牛客网暑期ACM多校训练营(第四场):A Ternary String(欧拉降幂)
链接:牛客网暑期ACM多校训练营(第四场):A Ternary String 题意:给出一段数列 s,只包含 0.1.2 三种数.每秒在每个 2 后面会插入一个 1 ,每个 1 后面会插入一个 0,之 ...
- CodeM美团点评编程大赛复赛 做题感悟&题解
[T1] [简要题意] 长度为N的括号序列,随机确定括号的方向:对于一个已确定的序列,每次消除相邻的左右括号(右左不行),消除后可以进一步合并和消除直到不能消为止.求剩下的括号的期望.\(N \l ...
- (luogu1704)寻找最优美做题曲线 [TPLY]
寻找最优美做题曲线 题目链接:https://www.luogu.org/problemnew/show/P1704 题目大意: 求包含指定点的最长不降子序列(严格递增) 题解 首先我们发现 一个序列 ...
- SDOI2016 R1做题笔记
SDOI2016 R1做题笔记 经过很久很久的时间,shzr终于做完了SDOI2016一轮的题目. 其实没想到竟然是2016年的题目先做完,因为14年的六个题很早就做了四个了,但是后两个有点开不动.. ...
- AtCoder Grand Contest 1~10 做题小记
原文链接https://www.cnblogs.com/zhouzhendong/p/AtCoder-Grand-Contest-from-1-to-10.html 考虑到博客内容较多,编辑不方便的情 ...
- noip做题记录+挑战一句话题解?
因为灵巧实在太弱辽不得不做点noip续下命QQAQQQ 2018 积木大赛/铺设道路 傻逼原题? 然后傻逼的我居然检查了半天是不是有陷阱最后花了差不多一个小时才做掉我做过的原题...真的傻逼了我:( ...
随机推荐
- FILE文件删除操作(删除指定文件夹下所有文件和文件夹包括子文件夹下所有文件和文件夹),就是删除所有
2018-11-05 19:42:08开始写 选择 删除 1.FileUtils.java类 import java.io.File;//导入包 import java.util.List;//导入 ...
- 用Django实现Video页面分类查询
Model表创建,Url映射,Views函数处理,Html生成 根据上图,视频方向与视频分类是多对多的关系,视频分类与视频信息是一对多的关系,难度级别是单一的查询条件(与之前俩者并无关系) Model ...
- 前端和后台BUG区分方法
测试工程师不只是负责发现问题,除了发现问题这种基本功外,定位问题,提出解决方案,提出预防方案也是要掌握的技能.这里先说定位问题的要求,定位问题要向深入,前提当然是对功能.产品的流程.开发方案.开发人员 ...
- jdk和jre区别
- 使用Groovy+Spock轻松写出更简洁的单测
当无法避免做一件事时,那就让它变得更简单. 概述 单测是规范的软件开发流程中的必不可少的环节之一.再伟大的程序员也难以避免自己不犯错,不写出有BUG的程序.单测就是用来检测BUG的.Java阵营中,J ...
- GJP_Project
1. view层作用: 视图层,即项目中的界面 l controller层作用: 控制层, 获取界面上的数据,为界面设置数据; 将要实现的功能交给业务层处理 l service层作用: 业务层, ...
- flask模板应用-消息闪现(flash())
消息闪现 flask提供了一个非常有用的flash()函数,它可以用来“闪现”需要提示给用户的消息,比如当用户登录成功后显示“欢迎回来!”.在视图函数调用flash()函数,传入消息内容,flash( ...
- linux基础命令---显示进程ps
ps ps指令可以显示系统中当前进程的信息,它的输出结果是高度可定制的.如果您希望重复更新所选内容和显示的信息,请使用top(1)代替. 请注意,“ps-aux”与“ps aux”不同.POSIX和U ...
- pxc集群进入非主模式怎么让最后的节点允许提供服务
这种情况一般是,集群其他节点意外宕机而最后一个节点无法自我仲裁,而进入非主模式. 该模式拒绝任何SQL的执行: ERROR 1047 (08S01): WSREP has not yet prepar ...
- Tensorflow学习笔记03-使用神经网络做线性回归
import tensorflow as tf import numpy as np #input就是输入数据,输入矩阵,in_size就是输入矩阵的列数(数据属性数量),out_size输出矩阵列数 ...