P3747 相逢是问候 欧拉定理+线段树
巨难!!!
去年六省联考唯一的一道黑牌题,我今天一天从早到晚,把它从暴力15分怼到了90分,极端接近正解了。
bzoj上A了,但是洛谷和loj上面就不行。伪正解会T,奇奇怪怪的类正解会WA。。
那么,网上的题解多得很,我就不细说了。
着重说一下我的理解感受和坑点。
1.不愧是黑牌题,显得十分的繁杂(并不)。
首先要用到扩展欧拉定理,φ(),还有线段树辅助,快速幂,大量奇奇怪怪的小细节.....要人命啊。
2.根据之前那题上帝集合,我们可以得知当一个数被操作很多很多很多很多次之后就不变了,成为一个常数。
3.我们首先算出这个次数:phi()到1就是了。特别的,phi(2)=1之后还要再写个phi(1)=1,否则会错。证明网上也很多,我比较推崇这个。(该证明并没有被再次找到......)
4.第一个坑点来了:(c^c^i)%p ≠ (c^((c^i)%p))%p 什么意思呢?意思就是你改一次之后不能接着改第二次,会WA。打暴力时就是这一点卡停了我的思路。如何解决:真·暴力!从初始值a[i]开始重新改起。我:......
5.解决了上面那一件事之后,我们开始着手研究扩展欧拉公式降次的那个式子。把(c^c^i)%p化开之后再一步步推下去,最后我们可以得到这么一个可爱的函数:
LL cal(int k,int t)
{
while(t>)
{
if(k>=p[t]) k=qpow(c,k%p[t]+p[t],p[t-]);
else k=qpow(c,k,p[t-]);
t--;
}
return k;
}
初等cal函数
看,它是如此的Cuty and goffy(?),这里有个p[]数组,是之前预处理出来的每一层phi(P)。
6.然后加上一个线段树,它滋磁区间求和,区间修改(每次修改到底),并记录一个times表示修改的次数。
7.当某次修改时,如果times已经=cnt了,就return。否则修改,update。
8.开开心心的一交,又WA又T......
9.仔细观察发现:那个可爱的cal中的判断条件if(k>=p[t])显然有误。原因是计算卡速米(kasumi)时已经把结果%p[t-1]了,而上一层的p[t-1]就是这一层的p[t],于是那个if不会触发。
10.翻看胡雨菲的题解,发现他把kasumi改了下,在kasumi里记录flag,保证了正确性。
11.交上去:T了两个点。90分,bzojAC。本着不放弃不抛弃的原则继续调试,发现要优化掉kasumi的时间复杂度,预处理一下。
12.那么怎么确定flag呢?①也预处理好。②每次在cal里记录一个tag,然后用log c p[t]<=tag来判定。
13.首先写①,写炸了。然后写②,解决了T但是又WA了,依旧90分。然后转①,继续炸。但是理论上两种方法都能AC。
14.over。
WA的代码就不放了。放个11.中的代码。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = ;
LL a[N],sum[N<<],times[N<<],p[N],c,P,cnt;
inline LL read()
{
LL ans=,f=;char ch=getchar();
while(ch<''||ch>'') {if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<='') {ans=ans*;ans+=(ch-'');ch=getchar();}
return ans*f;
}
inline LL qpow(LL a,LL b,LL m,bool &flag)
{
LL ans=;
flag=;
while(b)
{
if(b&)
{
ans=ans*a;
if(ans>=m) flag=,ans%=m;
}
b=b>>;
a=a*a;
if(a>=m) flag=,a%=m;
}
return ans;
}
inline LL phi(LL x)
{
LL ans=x;
for(register int i=;i*i<=x;i++)
{
if(x%i==)
{
while(x%i==) x/=i;
ans=(ans/i)*(i-);
}
}
if(x>) ans=(ans/x)*(x-);
return ans;
}
inline void pre()
{
p[]=P;
while(P>)
{
p[++cnt]=phi(P);
P=p[cnt];
}
p[++cnt]=;
P=p[];
return;
}
inline void update(LL l,LL r,LL o)
{
sum[o]=sum[o<<]+sum[o<<|];
times[o]=min(times[o<<],times[o<<|]);
return;
}
inline void build(LL l,LL r,LL o)
{
if(l==r)
{
sum[o]=a[r]%P;
return;
}
int mid=(l+r)>>;
build(l,mid,o<<);
build(mid+,r,o<<|);
update(l,r,o);
return;
}
inline LL cal(int k,int t)
{
bool flag=(k>=p[t]);
while(t>)
{
if(flag) k=qpow(c,k%p[t]+p[t],p[t-],flag);
else k=qpow(c,k,p[t-],flag);
t--;
}
return k;
}
inline void add(int L,int R,int l,int r,int o)
{
if(times[o]>=cnt) return;
if(l==r)
{
times[o]++;
sum[o]=cal(a[r],times[o]);
return;
}
int mid=(l+r)>>;
if(L<=mid) add(L,R,l,mid,o<<);
if(mid<R) add(L,R,mid+,r,o<<|);
update(l,r,o);
return;
}
inline LL ask(int L,int R,int l,int r,int o)
{
if(L<=l&&r<=R) return sum[o];
if(R<l||r<L) return ;
int mid=(l+r)>>;
return (ask(L,R,l,mid,o<<)+ask(L,R,mid+,r,o<<|))%P;
}
int main()
{
LL m,n;
//scanf("%lld%lld%lld%lld",&n,&m,&P,&c);
n=read();m=read();P=read();c=read();
for(register int i=;i<=n;i++) a[i]=read();//scanf("%lld",&a[i]);
pre();
build(,n,);
LL flag,x,y;
for(register int i=;i<=m;i++)
{
//scanf("%d%d%d",&flag,&x,&y);
flag=read();
x=read();y=read();
if(flag) printf("%lld\n",ask(x,y,,n,));
else add(x,y,,n,);
}
return ;
}
90分代码
题外话:可以看见我加了很多的常数优化,但是洛谷的#9和#11两个点剧毒。关于WA就放个链接吧,可以看出#3和#11比较毒,每次WA都有你们。
15分暴力->90分花了我一个上午。之后下午晚上都在优化那最后10分,还没搞出来。效率堪忧啊。其实可以搞一搞其他几道题的。
明天就是省选了。敬请收看:省选酱油记。
P3747 相逢是问候 欧拉定理+线段树的更多相关文章
- 【BZOJ4869】相逢是问候(线段树,欧拉定理)
[BZOJ4869]相逢是问候(线段树,欧拉定理) 题面 BZOJ 题解 根据欧拉定理递归计算(类似上帝与集合的正确用法) 所以我们可以用线段树维护区间最少的被更新的多少次 如果超过了\(\varph ...
- BZOJ4869 六省联考2017相逢是问候(线段树+欧拉函数)
由扩展欧拉定理,a^(a^(a^(……^x)))%p中x作为指数的模数应该是φ(φ(φ(φ(……p)))),而p取log次φ就会变为1,也即每个位置一旦被修改一定次数后就会变为定值.线段树维护区间剩余 ...
- bzoj 4869: [Shoi2017]相逢是问候 [扩展欧拉定理 线段树]
4869: [Shoi2017]相逢是问候 题意:一个序列,支持区间\(a_i \leftarrow c^{a_i}\),区间求和.在模p意义下. 类似于开根操作,每次取phi在log次后就不变了. ...
- SHOI 2017 相逢是问候(扩展欧拉定理+线段树)
题意 https://loj.ac/problem/2142 思路 一个数如果要作为指数,那么它不能直接对模数取模,这是常识: 诸如 \(c^{c^{c^{c..}}}\) 的函数递增飞快,不是高精度 ...
- BZOJ4869 [Shoi2017]相逢是问候 【扩展欧拉定理 + 线段树】
题目链接 BZOJ4869 题解 这题调得我怀疑人生,,结果就是因为某些地方\(sb\)地忘了取模 前置题目:BZOJ3884 扩展欧拉定理: \[c^a \equiv c^{a \mod \varp ...
- [BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)
4869: [Shoi2017]相逢是问候 Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 1313 Solved: 471[Submit][Stat ...
- 【BZOJ4869】相逢是问候 [线段树][欧拉定理]
相逢是问候 Time Limit: 40 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description Informatikverbin ...
- 【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理
Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两 ...
- LOJ #2142. 「SHOI2017」相逢是问候(欧拉函数 + 线段树)
题意 给出一个长度为 \(n\) 的序列 \(\{a_i\}\) 以及一个数 \(p\) ,现在有 \(m\) 次操作,每次操作将 \([l, r]\) 区间内的 \(a_i\) 变成 \(c^{a_ ...
随机推荐
- Jmeter(三十二)_搭建本地接口自动化环境
我们在学习接口自动化的时候,最理想的状态是在公司有项目可以操作.大部分时候我们并没有可以练习的项目,因此练习接口无从谈起,只能找一些开放的api来练一练,但是这样并不能提高我们的技术.因此我们需要搭建 ...
- React.js 开发参见问题 Q&A
文章中我整理了 React.js 开发过程中一些参见问题的解答汇总,供大家参考. 1. 一些课程资源 课程完整的思维导图请查考文章:React.js 入门与实战课程思维导图,我使用的思维导图软件是 M ...
- 分布式监控系统Zabbix--完整安装记录 -添加web页面监控
通过zabbix做web监控,不仅仅可以监控到站点的响应时间,还可以根据站点返回的状态码或响应时间做报警设置,比如说对某个url进行监控,当访问返回的状态码是非200状态时都报警(创建触发器即可).下 ...
- Tomcat利用MSM实现Session共享方案解说
Session共享有多种解决方法,常用的有四种:1)客户端Cookie保存2)服务器间Session同步3)使用集群管理Session(如MSM) 4)把Session持久化到数据库 针对上面Sess ...
- mysql操作命令梳理(2)-alter(update、insert)
在mysql运维操作中会经常使用到alter这个修改表的命令,alter tables允许修改一个现有表的结构,比如增加或删除列.创造或消去索引.改变现有列的类型.或重新命名列或表本身,也能改变表的注 ...
- omnigraffle 的一些总结
http://jingyan.baidu.com/article/fcb5aff7a16337edab4a714d.html Omnigraffle绘制连接线时从任意点开始 点击直线工具后,在右侧设置 ...
- 个人作业Week2-代码复审(修改明确了要求)
代码复审 零,说在前面的话 大家完成了个人项目之后,都写了很多代码. 这些代码可能: 大括号换行/不换行 使用tab缩进/使用空格缩进 变量名函数名的定义很好/不好 每个函数都有详细的注释解释函数的功 ...
- final个人阅读作业
一.软件工程M1/M2总结 1.M1阶段总结: 我们团队的软件工程开发是按照前后端来分别开发的,我是负责后端的.我们的项目是做一个北航的社团平台,是一个网站.在后端我们使用的是ruby on rail ...
- Linux 下如何知道是否有人在使坏?
在 Linux 下查看用户的行为,不仅仅是网管要做的事,也是开发人员所应该具备的基本技能之一.为什么呢?因为有时其他同事在做一些很消耗资源的事情,比如在编译大型程序,可能会导致服务器变得很慢,从而影响 ...
- [转帖]Linux的进程线程及调度
Linux的进程线程及调度 本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10393707.html 本文为宋宝华<Linux的进程 ...