bzoj4869 [Shoi2017]相逢是问候

http://www.elijahqi.win/2018/03/08/bzoj4869/
Description

Informatikverbindetdichundmich.
信息将你我连结。B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数。一共有m个操作,可以
分为两种:0 l r表示将第l个到第r个数(al,al+1,…,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是
输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为
这个结果可能会很大,所以你只需要输出结果mod p的值即可。

Input

第一行有三个整数n,m,p,c,所有整数含义见问题描述。
接下来一行n个整数,表示a数组的初始值。
接下来m行,每行三个整数,其中第一个整数表示了操作的类型。
如果是0的话,表示这是一个修改操作,操作的参数为l,r。
如果是1的话,表示这是一个询问操作,操作的参数为l,r。
1 ≤ n ≤ 50000, 1 ≤ m ≤ 50000, 1 ≤ p ≤ 100000000, 0 < c < p, 0 ≤ ai < p

Output

对于每个询问操作,输出一行,包括一个整数表示答案mod p的值。

Sample Input

4 4 7 2
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3
Sample Output

0
3
HINT

鸣谢多名网友提供正确数据,已重测!

Source

这题不知道欧拉函数 降幂公式真没法做 全程感谢tgptp&zyy的支持 才让辣鸡蒟蒻我做完了这题

首先欧拉函数是< n的所有正整数里于n互质的有多少个 有个性质在于如果n!=2那么一定函数值是偶数也是后面保证复杂度的前提

公式

利用这个公式记得只有在>=phi[p]的时候才成立 但是记得某个巨佬里提到过如果不判断这个条件也只会在n=6的时候失效所以数据可以不判断

A^B(mod p)≡A^(b%φ(p)+φ(p)) 因为上面提到的性质 所以这个φ(p)最多递归Log次 注意当为1的时候也需要递归 具体原因在bzoj的discuss里面提到过 为什么这个是对的 直接搞指数取mod为什么不对 因为我要取的mod不是p而是φ(p)或者φ(φ(p)) 那么这样的话做法就类似之前的一个cf题 每次做的时候判断这个区间是否已经被做了log次了如果是这样 好这个区间答案不会再改变了 否则暴力改下去 复杂度均摊log(n)算上一共是n*log(n)个区间 还有每次快速幂的log 一共是log^3我的尝数不优秀直接tle了那么考虑怎么优化 看了看题解我可以前 2^16 分一组 后2^16分一组 因为底数都是相同的所以可以直接预处理出来做到近似o(1)回答

n*log(n)^2

#include<cmath>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 55000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
struct node{
    int left,right,sum,cnt;bool tag;
}tree[N<<1];
int phi[31],num,tot,n,m,p,c,a[N],root,table[31][1<<17],table1[31][1<<17];
inline int c_p(int x){
    int tmp=x;
    for (int i=2;i<=sqrt(x);++i) {
        if (x%i) continue;tmp=tmp/i*(i-1);
        while(x%i==0) x/=i;
    }if (x!=1) tmp/=x,tmp*=(x-1);
    return tmp;
}
inline int pow(int x,int t,int mod){
    int tmp=1;
    for (;t;x=(ll)x*x%mod,t>>=1) if (t&1) tmp=(ll)tmp*x%mod;
    return tmp;
}
inline void init(){
    for (int i=0;i<=tot;++i){
        int tmp=pow(c,1<<16,phi[i]);table[i][0]=table1[i][0]=1;
        for (int j=1;j<(1<<16);++j){
            table[i][j]=(ll)table[i][j-1]*c%phi[i];
            table1[i][j]=(ll)table1[i][j-1]*tmp%phi[i];
        }

    }
}
inline void update(int x){
    int l=tree[x].left,r=tree[x].right;tree[x].tag=1;
    tree[x].sum=(tree[l].sum+tree[r].sum)%p;
    if (l)tree[x].tag&=tree[l].tag;if(r) tree[x].tag&=tree[r].tag;
}
inline void build(int &x,int l,int r){
    x=++num;if (l==r) {tree[x].sum=a[l];return;}
    int mid=l+r>>1; build(tree[x].left,l,mid);
    build(tree[x].right,mid+1,r);update(x);
}
inline int pow1(int x,int md){
    return (ll)table[md][x&((1<<16)-1)]*table1[md][x>>16]%phi[md];
}
inline int calc(int x,int t){
    int tmp=x;if (tmp>phi[t]) tmp=tmp%phi[t]+phi[t];
    while(t--){
        tmp=pow1(tmp,t);if (!tmp&&t) tmp+=phi[t];
    }return tmp%phi[0];
}
inline void insert1(int x,int l,int r,int l1,int r1){
    if (l1<=l&&r1>=r&&tree[x].tag) return;int mid=l+r>>1;
    if (l==r) {
        ++tree[x].cnt;tree[x].sum=calc(a[l],tree[x].cnt);
        if (tree[x].cnt==tot) tree[x].tag=1;return;
    }
    if (l1<=mid) insert1(tree[x].left,l,mid,l1,r1);
    if (r1>mid) insert1(tree[x].right,mid+1,r,l1,r1);update(x);
}
inline int query(int x,int l,int r,int l1,int r1){
    if (l1<=l&&r1>=r) return tree[x].sum;int mid=l+r>>1,tmp=0;
    if (l1<=mid) tmp+=query(tree[x].left,l,mid,l1,r1);
    if (r1>mid) tmp+=query(tree[x].right,mid+1,r,l1,r1);return tmp%p;
}
inline void print(int x,int l,int r){
    int mid=l+r>>1;
    if (tree[x].left) print(tree[x].left,l,mid);
    printf("%d %d %d\n",l,r,tree[x].sum);
    if (tree[x].right) print(tree[x].right,mid+1,r); 
}
int main(){
    //freopen("bzoj4869.in","r",stdin);
    //freopen("bzoj4869.out","w",stdout);
    n=read();m=read();p=read();c=read();
    phi[0]=p;tot=0;while(phi[tot]-1) ++tot,phi[tot]=c_p(phi[tot-1]);phi[++tot]=1;
    //for (int i=0;i<=tot;++i) printf("%d ",phi[i]);puts("");
    init();
    for (int i=1;i<=n;++i) a[i]=read();build(root,1,n);
    for (int i=1;i<=m;++i){
        int op=read(),l=read(),r=read();
        if(op==0) insert1(root,1,n,l,r);else printf("%d\n",query(root,1,n,l,r));
    //  print(root,1,n);puts("--------");
    }//puts("");
    return 0;
}

n*log(n)^3

#include<cmath>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 55000
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
struct node{
    int left,right,sum,cnt;bool tag;
}tree[N<<1];
int phi[31],num,tot,n,m,p,c,a[N],root;
inline int c_p(int x){
    int tmp=x;
    for (int i=2;i<=sqrt(x);++i) {
        if (x%i) continue;tmp=tmp/i*(i-1);
        while(x%i==0) x/=i;
    }if (x!=1) tmp/=x,tmp*=(x-1);
    return tmp;
}
inline void update(int x){
    int l=tree[x].left,r=tree[x].right;tree[x].tag=1;
    tree[x].sum=(tree[l].sum+tree[r].sum)%p;
    if (l)tree[x].tag&=tree[l].tag;if(r) tree[x].tag&=tree[r].tag;
}
inline void build(int &x,int l,int r){
    x=++num;if (l==r) {tree[x].sum=a[l];return;}
    int mid=l+r>>1; build(tree[x].left,l,mid);
    build(tree[x].right,mid+1,r);update(x);
}
inline int pow(int x,int t,int mod,bool &pd){
    int tmp=1;
    for (;t;pd|=(ll)x*x>=mod,x=(ll)x*x%mod,t>>=1) {
        if (t&1) pd|=(ll)tmp*x>=mod,tmp=(ll)tmp*x%mod;
    }return tmp;
}
inline int calc(int x,int t){
    int tmp=x;if (tmp>phi[t]) tmp=tmp%phi[t]+phi[t];
    while(t--){
        bool pd=0;
        tmp=pow(c,tmp,phi[t],pd);if (pd) tmp+=phi[t];
    }return tmp%phi[0];
}
inline void insert1(int x,int l,int r,int l1,int r1){
    if (l1<=l&&r1>=r&&tree[x].tag) return;int mid=l+r>>1;
    if (l==r) {
        ++tree[x].cnt;tree[x].sum=calc(a[l],tree[x].cnt);
        if (tree[x].cnt==tot) tree[x].tag=1;return;
    }
    if (l1<=mid) insert1(tree[x].left,l,mid,l1,r1);
    if (r1>mid) insert1(tree[x].right,mid+1,r,l1,r1);update(x);
}
inline int query(int x,int l,int r,int l1,int r1){
    if (l1<=l&&r1>=r) return tree[x].sum;int mid=l+r>>1,tmp=0;
    if (l1<=mid) tmp+=query(tree[x].left,l,mid,l1,r1);
    if (r1>mid) tmp+=query(tree[x].right,mid+1,r,l1,r1);return tmp%p;
}
inline void print(int x,int l,int r){
    int mid=l+r>>1;
    if (tree[x].left) print(tree[x].left,l,mid);
    printf("%d %d %d\n",l,r,tree[x].sum);
    if (tree[x].right) print(tree[x].right,mid+1,r); 
}
int main(){
    //freopen("bzoj4869.in","r",stdin);
    //freopen("bzoj4869.out","w",stdout);
    n=read();m=read();p=read();c=read();
    phi[0]=p;tot=0;while(phi[tot]-1) ++tot,phi[tot]=c_p(phi[tot-1]);phi[++tot]=1;
    //for (int i=0;i<=tot;++i) printf("%d ",phi[i]);puts("");
    for (int i=1;i<=n;++i) a[i]=read();build(root,1,n);
    for (int i=1;i<=m;++i){
        int op=read(),l=read(),r=read();
        if(op==0) insert1(root,1,n,l,r);else printf("%d\n",query(root,1,n,l,r));
    //  print(root,1,n);puts("--------");
    }//puts("");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值