[codeforces]Round #538 (Div. 2) F. Please, another Queries on Array?

题解:

     $$  ans=F\left ( \prod _{i=l}^{r}a_i \right ) $$

   $$ =(p_i-1){p_i}^{k_i-1}*.....*(p_j-1){p_j}^{k_j-1} $$

   $$={p_i}^{k_i}*.....*{p_j}^{k_j}*(\frac{p_i-1}{p_i}*......*\frac{p_j-1}{p_j})  $$

   因为数据范围保证$ a_i\leq 300 $ 所以在这个范围内只有62个素因子  我们可以直接每一位对应一bit  来判断区间中某个素因子是否出现 然后查询就行了

(常数写的有点大....懒得优化了

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=4e5+10;
const double eps=1e-8;
#define ll long long
const int mod=1e9+7;
using namespace std;
struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;}
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}

ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
	if(b&1)ans=ans*a%mod;
	a=a*a%mod;b=b>>1;
    }
    return ans;
}

ll key[MAXN<<2],tag[MAXN<<2],sum[MAXN<<2],flag[MAXN<<2];
int a[MAXN];
int vis[305],p[MAXN];

void push(int rt,int l,int r){
    if(tag[rt]!=1){
	int mid=(l+r)>>1;
	tag[rt<<1]*=tag[rt];tag[rt<<1]%=mod;
	tag[rt<<1|1]*=tag[rt];tag[rt<<1|1]%=mod;
	sum[rt<<1]*=ksm(tag[rt],mid-l+1);sum[rt<<1]%=mod;
	sum[rt<<1|1]*=ksm(tag[rt],r-mid);sum[rt<<1|1]%=mod;
	tag[rt]=1;
    }
    if(flag[rt]){
	key[rt<<1]|=flag[rt];key[rt<<1|1]|=flag[rt];
	flag[rt<<1]|=flag[rt];flag[rt<<1|1]|=flag[rt];
	flag[rt]=0;
    }
}

void up(int x){
    key[x]=(key[x<<1]|key[x<<1|1]);
    sum[x]=(sum[x<<1]*sum[x<<1|1])%mod;
}

void built(int rt,int l,int r){
    tag[rt]=1;
    if(l==r){
	sum[rt]=1;
	for(int i=2;i*i<=a[l];i++){
	    if(a[l]%i==0){
		int num=0;
		while(a[l]%i==0)num++,a[l]/=i;
		sum[rt]=sum[rt]*ksm(i,num)%mod;
		key[rt]|=(1LL<<vis[i]);
	    }
	}
	if(a[l]!=1){
	    sum[rt]=(sum[rt]*a[l])%mod;
	    key[rt]|=(1LL<<vis[a[l]]);
	}
	return ;
    }
    int mid=(l+r)>>1;
    built(rt<<1,l,mid);
    built(rt<<1|1,mid+1,r);
    up(rt);
}

ll v1,v2;

void update(int rt,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
	tag[rt]*=v1;tag[rt]%=mod;flag[rt]|=v2;
	sum[rt]*=ksm(v1,r-l+1);key[rt]|=v2;
	return ;
    }
    int mid=(l+r)>>1;
    push(rt,l,r);
    if(ql<=mid)update(rt<<1,l,mid,ql,qr);
    if(qr>mid)update(rt<<1|1,mid+1,r,ql,qr);
    up(rt);
}

ll ans1,ans2;
void query(int rt,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
	ans1*=sum[rt];ans1%=mod;ans2|=key[rt];
	return ;
    }
    int mid=(l+r)>>1;
    push(rt,l,r);
    if(ql<=mid)query(rt<<1,l,mid,ql,qr);
    if(qr>mid)query(rt<<1|1,mid+1,r,ql,qr);
    up(rt);
}

int main(){
    int cnt=0;
    inc(i,2,300){
	bool flag=0;
	for(int j=2;j*j<=i;j++){
	    if(i%j==0){flag=1;break;}
	}
	if(!flag)vis[i]=cnt++,p[cnt-1]=i;
    }
    int n=read();int m=read();
    inc(i,1,n)a[i]=read();
    built(1,1,n);
    char str[11];int l,r,x;
    while(m--){
	scanf("%s",str);
	l=read();r=read();
	if(str[0]==‘T‘){
	    ans1=1;ans2=0;query(1,1,n,l,r);
	    for(int i=61;i>=0;i--){
		if((ans2>>i)&1)ans1*=((p[i]-1)*ksm(p[i],mod-2)%mod),ans1%=mod;
	    }
	    printf("%lld\n",ans1);
	}
	else{
	    x=read();
	    v1=1;v2=0;
	    for(int i=2;i*i<=x;i++){
		    if(x%i==0){
		    int num=0;
			while(x%i==0)num++,x/=i;
			v1=v1*ksm(i,num)%mod;
			v2|=(1LL<<vis[i]);
		}
	    }
	    if(x!=1){
		v1=(v1*x)%mod;
		v2|=(1LL<<vis[x]);
	    }
	    update(1,1,n,l,r);
	}
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/wang9897/p/10360754.html

时间: 2024-11-05 19:23:20

[codeforces]Round #538 (Div. 2) F. Please, another Queries on Array?的相关文章

Codeforces Round #538 (Div. 2) (CF1114)

Codeforces Round #538 (Div. 2) (CF1114) ??今天昨天晚上的cf打的非常惨(仅代表淮中最低水平 ??先是一路缓慢地才A掉B,C,然后就开始杠D.于是写出了一个O(n^2)的线性dp,然后就wa6,调到结束.结束后发现完全看漏了两句话.噢,起始点!!! ??好吧然后算算自己有可能这一场要变成+0,反正在0左右. 结束后开始然后开始写D,顺便思考F.结果写完D发现A怎么fst了,然后...因为习惯于对相似的语句复制粘贴,有些东西没有改--三句话都在 -a!!!(

Codeforces Round #486 (Div. 3) F. Rain and Umbrellas

Codeforces Round #486 (Div. 3) F. Rain and Umbrellas 题目连接: http://codeforces.com/group/T0ITBvoeEx/contest/988/problem/E Description Polycarp lives on a coordinate line at the point x=0. He goes to his friend that lives at the point x=a. Polycarp can

Codeforces Round #501 (Div. 3) F. Bracket Substring

题目链接 Codeforces Round #501 (Div. 3) F. Bracket Substring 题解 官方题解 http://codeforces.com/blog/entry/60949 ....看不懂 设dp[i][j][l]表示前i位,左括号-右括号=j,匹配到l了 状态转移,枚举下一个要填的括号,用next数组求状态的l,分别转移 代码 #include<bits/stdc++.h> using namespace std; const int maxn = 207;

递推 Codeforces Round #186 (Div. 2) B. Ilya and Queries

题目传送门 1 /* 2 递推:用cnt记录前缀值,查询区间时,两个区间相减 3 */ 4 #include <cstdio> 5 #include <algorithm> 6 #include <cmath> 7 #include <cstring> 8 using namespace std; 9 10 const int MAXN = 1e5 + 10; 11 const int INF = 0x3f3f3f3f; 12 char s[MAXN]; 1

Codeforces Round #216 (Div. 2) E. Valera and Queries (BIT)

题目大意: 给出很多条分布在 x 轴上的线段. 然后给出很多点集,问这些点集分布在多少条不同的线段上. 思路分析: 把点集分散成若干条线段. 如果点集做出的线段包含了某一条给出的线段的话,也就是说这个点集上不会有点在这条线段上. 所以我们就是求出 点集做出的线段包含了多少个给出的线段就可以了. 那么也就是比较l r的大小,排序之后用BIT #include <cstdio> #include <iostream> #include <algorithm> #includ

Codeforces Round #538 (Div. 2)

目录 Codeforces 1114 A.Got Any Grapes? B.Yet Another Array Partitioning Task C.Trailing Loves (or L'oeufs?) D.Flood Fill(区间DP) E.Arithmetic Progression(交互 二分 随机化) F.Please, another Queries on Array?(线段树 欧拉函数) Codeforces 1114 比赛链接 貌似最近平均难度最低的一场div2了...

Codeforces Round #392 (Div. 2) F. Geometrical Progression

原题地址:http://codeforces.com/contest/758/problem/F F. Geometrical Progression time limit per test 4 seconds memory limit per test 256 megabytes input standard input output standard output For given n, l and r find the number of distinct geometrical pro

Codeforces Round #531 (Div. 3) F. Elongated Matrix(状压DP)

F. Elongated Matrix 题目链接:https://codeforces.com/contest/1102/problem/F 题意: 给出一个n*m的矩阵,现在可以随意交换任意的两行,最后从上到下,从左到右形成一个序列s1,s2.....snm,满足对于任意相邻的两个数,它们差的绝对值的最大值为k. 现在问怎么交换行与行,可以使得最后的这个k最大. 题解: 人生中第一道状压dp~其实还是参考了这篇博客:https://blog.csdn.net/CSDNjiangshan/art

Codeforces Round #548 (Div. 2) F splay(新坑) + 思维

https://codeforces.com/contest/1139/problem/F 题意 有m个人,n道菜,每道菜有\(p_i\),\(s_i\),\(b_i\),每个人有\(inc_j\),\(pref_j\),一个人可以买一道菜的条件是 1. \(p_i \leq inc_j \leq s_i\) 2. \(|b_i - pref_j| \leq inc_j-p_i\) ,问每个人分别能买多少道菜 题解 转化一下公式 \(p_i \leq inc_j \leq s_i\) 下面两个满