这题我在考场上也是想出了正解的……但是没调出来。

题目链接:CF原网

题目大意:给一个长度为 $n$ 的序列 $a$,$q$ 个操作:区间乘 $x$,求区间乘积的欧拉函数模 $10^9+7$ 的值。

$1\le n\le 4\times 10^5,1\le q\le 2\times 10^5,1\le a_i,x\le 300$。时限 5.5s,空限 256MB。


明显线段树。

有一个想法是维护区间积的欧拉函数,但是这样时间复杂度和代码复杂度都很高……

我的做法是维护区间积。而欧拉函数,就是看看区间中包含什么质因子,然后除一下乘一下好了。

区间积就不用说了。

包含什么质因子?难道要开bool数组吗?时间复杂度很高……

经过后台黑科技操作发现 $300$ 以内的质数只有 $62$ 个。明摆着状压的节奏!

好的,这题做完了。细节的东西在代码中都有。

对于我的代码实现来说:(以下令 $k=62$)

建树 $O(kn)$。

合并节点 $O(1)$。

下推标记 $O(\log n)$。

区间乘 $O(\log^2 n+k)$。

查询欧拉函数 $O(\log n+k)$。

总时间复杂度应该是 $O((n+q)k+q\log^2n)$。其实跑得不慢,我跑得最慢的点是1934ms。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=,mod=;
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
char ch=getchar();int x=,f=;
while(ch<'' || ch>'') f|=ch=='-',ch=getchar();
while(ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return f?-x:x;
}
int n,q,pri[],pl,a[maxn],inv[],f[],tag1[maxn*]; //tag1表示区间要乘多少
ll tag2[maxn*]; //tag2表示区间会多出哪些质因子(也是压缩过的)
//为什么要两个标记呢?不能直接对tag1分解质因子吗?
//因为tag1乘几遍就会被取模,这样看起来质因子就变了。所以额外加一个tag2表示真的质因子集合。
bool vis[];
void init(){
FOR(i,,){
if(!vis[i]) pri[++pl]=i;
for(int j=;j<=pl && i*pri[j]<=;j++){
vis[i*pri[j]]=true;
if(i%pri[j]==) break;
}
}
inv[]=;
FOR(i,,) inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
FOR(i,,pl) f[i]=1ll*inv[pri[i]]*(pri[i]-)%mod;
//f[i]表示除以p[i],再乘上p[i]-1,便于计算欧拉函数
}
inline int qpow(int a,int b){
int ans=;
for(;b;b>>=,a=1ll*a*a%mod) if(b&) ans=1ll*ans*a%mod;
return ans;
}
struct node{
int pro;ll has;
}nd[maxn*]; //一个线段树节点,pro是区间积,has是区间包含哪些质因子(压缩过的)
void pushup(node &o,node l,node r){ //合并
o.has=l.has|r.has; //直接取或
o.pro=1ll*l.pro*r.pro%mod;
}
void setmult(int o,int l,int r,int x,ll y){ //对第o个节点(管辖[l,r])区间乘x,质因子多了y
tag1[o]=1ll*tag1[o]*x%mod;
tag2[o]|=y;
nd[o].pro=1ll*nd[o].pro*qpow(x,r-l+)%mod; //记得乘r-l+1次方
nd[o].has|=y;
}
void pushdown(int o,int l,int r){ //下传标记
if(!tag2[o]) return;
int mid=(l+r)>>;
setmult(lson,tag1[o],tag2[o]);
setmult(rson,tag1[o],tag2[o]);
tag1[o]=;tag2[o]=; //记得tag1闲置时是1
}
void build(int o,int l,int r){
tag1[o]=;tag2[o]=;
if(l==r){
nd[o].pro=a[l];
FOR(i,,pl) //记录质因子集合
if(a[l]%pri[i]==) nd[o].has|=1ll<<(i-);
return;
}
int mid=(l+r)>>;
build(lson);build(rson);
pushup(nd[o],nd[o<<],nd[o<<|]);
}
void mult(int o,int l,int r,int ql,int qr,int x,ll y){ //外面调用时先把质因子集合弄好,会省时间
if(l>=ql && r<=qr){
setmult(o,l,r,x,y); //直接设上
return;
}
pushdown(o,l,r);
int mid=(l+r)>>;
if(mid>=ql) mult(lson,ql,qr,x,y);
if(mid<qr) mult(rson,ql,qr,x,y);
pushup(nd[o],nd[o<<],nd[o<<|]);
}
node query(int o,int l,int r,int ql,int qr){
if(l>=ql && r<=qr) return nd[o];
pushdown(o,l,r);
int mid=(l+r)>>;
if(mid<ql) return query(rson,ql,qr);
if(mid>=qr) return query(lson,ql,qr);
node ans;
pushup(ans,query(lson,ql,qr),query(rson,ql,qr)); //合并两边
return ans;
}
int main(){
init();
n=read();q=read();
FOR(i,,n) a[i]=read();
build(,,n);
FOR(i,,q){
char op[];
scanf("%s",op);
int l=read(),r=read();
if(op[]=='M'){ //乘操作
int x=read();ll y=;
FOR(i,,pl) if(x%pri[i]==) y|=1ll<<(i-); //先处理质因子集合
mult(,,n,l,r,x,y);
}
else{ //求欧拉函数操作
node ans=query(,,n,l,r);
int s=ans.pro; //区间积
FOR(i,,pl) if(ans.has&(1ll<<(i-))) s=1ll*s*f[i]%mod; //区间含有第i个质数,那就要除以p[i],再乘上p[i]-1
printf("%d\n",s);
}
}
}

CF1114F Please, another Queries on Array?(线段树,数论,欧拉函数,状态压缩)的更多相关文章

  1. Codeforces 1114F Please, another Queries on Array? [线段树,欧拉函数]

    Codeforces 洛谷:咕咕咕 CF少有的大数据结构题. 思路 考虑一些欧拉函数的性质: \[ \varphi(p)=p-1\\ \varphi(p^k)=p^{k-1}\times (p-1)= ...

  2. BZOJ 4026 dC Loves Number Theory (主席树+数论+欧拉函数)

    题目大意:给你一个序列,求出指定区间的(l<=i<=r) mod 1000777 的值 还复习了欧拉函数以及线性筛逆元 考虑欧拉函数的的性质,(l<=i<=r),等价于 (p[ ...

  3. [Codeforces 266E]More Queries to Array...(线段树+二项式定理)

    [Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...

  4. Codeforces 1114F Please, another Queries on Array? 线段树

    Please, another Queries on Array? 利用欧拉函数的计算方法, 用线段树搞一搞就好啦. #include<bits/stdc++.h> #define LL ...

  5. 暑假集训单切赛第一场 CF 266E More Queries to Array(线段树+二项式展开式)

    比赛时,第二题就是做的这个,当时果断没仔细考虑,直接用线段树暴力求.结果易想而知,超时了. 比赛后搜了搜题解,恍然大悟. 思路:显然用线段树,但是由于每次查询都会有变,所以不可能存储题目中的式子.   ...

  6. [Codeforces266E]More Queries to Array...——线段树

    题目链接: Codeforces266E 题目大意:给出一个序列$a$,要求完成$Q$次操作,操作分为两种:1.$l,r,x$,将$[l,r]$的数都变为$x$.2.$l,r,k$,求$\sum\li ...

  7. CF383C Propagating tree (线段树,欧拉序)

    \(tag\)没开够\(WA\)了一发... 求出\(dfs\)序,然后按深度分类更新与查询. #include <iostream> #include <cstdio> #i ...

  8. Please, another Queries on Array?(Codeforces Round #538 (Div. 2)F+线段树+欧拉函数+bitset)

    题目链接 传送门 题面 思路 设\(x=\prod\limits_{i=l}^{r}a_i\)=\(\prod\limits_{i=1}^{n}p_i^{c_i}\) 由欧拉函数是积性函数得: \[ ...

  9. CF1114F Please, another Queries on Array?

    CF1114F Please, another Queries on Array? 考虑用线段树维护取模后的区间积和真正的区间积所含有的质因子. 每次询问查得这两个值后,一乘一除,即可算出该区间积的欧 ...

随机推荐

  1. Caffe源码中caffe.proto文件分析

    Caffe源码(caffe version:09868ac , date: 2015.08.15)中有一些重要文件,这里介绍下caffe.proto文件. 在src/caffe/proto目录下有一个 ...

  2. Visual Studio2017 Remote Debugger

    前言 大家在使用vs打包后的文件部署到服务器后,有时候我们需要对线网的后台进行调试.但是它不像在VS中.这个时候我们该怎么调试呢? 微软想到了这一点,他们在 VS 中给我们提供了一个功能: Remot ...

  3. React之父子组件传递和其它一些要点

    react是R系技术栈中最基础同时也是最核心的一环,2年不到获取了62.5k star(截止到目前),足可见其给力程度.下面对一些react日常开发中的注意事项进行罗列. React的组件生命周期 r ...

  4. 腾讯云COS体验

    其实这篇文章本来是推荐COS的,写了一半发现COS的免费额度取消了,2019年之后的开通的用户免费6个月,老用户不受影响,这还让我怎么推荐啊?!写都写了,删掉岂不是白浪费时间? 都怪你!腾讯云! 起因 ...

  5. linux下expect环境安装以及简单脚本测试

    expect是交互性很强的脚本语言,可以帮助运维人员实现批量管理成千上百台服务器操作,是一款很实用的批量部署工具!expect依赖于tcl,而linux系统里一般不自带安装tcl,所以需要手动安装 下 ...

  6. Web系统页面打印技术实现与分析

    1 Web页面打印概述应用WEB化,不论对开发商,还是对用户来说,实在是一种很经济的选择,因为基于WEB的应用,客户端的规则很简单,容易学习,容易维护,容易发布.在WEB系统中,打印的确是个烦人的问题 ...

  7. 生产者消费者模式 php 【转】

    在工作中常常听到某某大牛之间的交谈会涉及到,xx消费者啊啥的,到底什么大牛之间讲的是什么? 这篇文章主要解决三个问题: 1.到底什么是生产者和消费者,以及它们之间的故事 2.它们之间靠什么交流 3.应 ...

  8. Java的首次学习和了解

    先来说说自己对于Java的了解.Java是一种面向对象的语言,而c++则是面向过程的.Java在网页的开发设计制作过程中必不可少,另外我们还可以用它来做手机的移动开发,还有一些基于服务器的架构设计.J ...

  9. C#JSON与XML转换

    C#JSON转XML 输入:[{\'name\': \'yancy\',\'value\': \'0\'},{\'name\': \'jieny\',\'value\': \'1\'}] string ...

  10. CentOS查看版本及架构信息

    https://blog.csdn.net/shuaigexiaobo/article/details/78030008