zoukankan      html  css  js  c++  java
  • [SHOI2017]相逢是问候

    Description

    信息将你我连结。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
     
    扩展欧拉定理:
    $a^{b} mod p=a^{b mod varphi(p)+varphi(p)}$,如果$b<varphi(p)$则不加$varphi(p)$。
    因为一个数取cnt=log次Φ变换就会变成1,一个数变换log次以后就不会变了。
    所以用线段树维护一个点的变换次数k
    区间修改要修改到每个点,只要判断大于变换次数大于cnt时不换(换了也一样)
    根据分析,复杂度最多nlogn
    然后直接从cnt往1一步一步模拟变换算出结果,然后快速幂,计算过程O(logn*logn)
    这样有O(nlog3n),会超时
    这时可以把10^9分成两个4位部分,预处理然后询问O(1)
    代码1勉强能过90分,总用时24572ms
    代码2有100分,总用时7288ms
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 typedef long long lol;
      8 int n,m;
      9 int c,ans;
     10 int sum[400001],a[100001];
     11 int phi[10001],cnt,ts[400001];
     12 int get_phi(int N)
     13 {int i;
     14   int res=N,x=N;
     15   for (i=2;i*i<=N;i++)
     16     {
     17       if (x%i) continue;
     18       res=res/i*(i-1);
     19       while (x%i==0) x/=i;
     20     }
     21   if (x!=1) res=res/x*(x-1);
     22   return res;
     23 }
     24 void pre(lol p)
     25 {
     26   phi[0]=p;cnt=0;
     27   while (p!=1)
     28     {
     29       int t=get_phi(p);
     30       phi[++cnt]=t;
     31       p=t;
     32     }
     33   phi[++cnt]=1;
     34 }
     35 int qpow(int x,int y,int p,bool &ok)
     36 {
     37   int res=1;ok=0;
     38   while (y)
     39     {
     40       if (res*x>=p) ok=1;
     41       if (y&1) res=1ll*res*x%p;
     42       x=1ll*x*x%p;
     43       y>>=1;
     44     }
     45   return res;
     46 }
     47 int cal(int x,int k)
     48 {
     49   int res=x;
     50   bool ok;
     51   if (x>=phi[k]) res=res%phi[k]+phi[k];
     52   while (k)
     53     {
     54       res=qpow(c,res,phi[k-1],ok);
     55       if (ok) res+=phi[k-1];
     56       k--;
     57     }
     58   return res;
     59 }
     60 void build(int rt,int l,int r)
     61 {
     62   if (l==r)
     63     {
     64       sum[rt]=a[l]%phi[0];
     65       return;
     66     }
     67   int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1;
     68   build(ls,l,mid);
     69   build(rs,mid+1,r);
     70   sum[rt]=(sum[ls]+sum[rs])%phi[0];
     71 }
     72 void update(int rt,int l,int r,int L,int R)
     73 {
     74   if (ts[rt]>=cnt) return;
     75   if (l==r)
     76     {
     77       ts[rt]++;
     78       sum[rt]=cal(a[l],ts[rt]);
     79       return;
     80     }
     81   int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1;
     82   if (L<=mid) update(ls,l,mid,L,R);
     83   if (R>mid) update(rs,mid+1,r,L,R);
     84   sum[rt]=(sum[ls]+sum[rs])%phi[0];
     85   ts[rt]=min(ts[ls],ts[rs]);
     86 }
     87 lol query(int rt,int l,int r,int L,int R)
     88 {
     89   if (l>=L&&r<=R)
     90     {
     91       return sum[rt];
     92     }
     93   int mid=(l+r)/2,ls=rt<<1,rs=rt<<1|1;
     94   lol s=0;
     95   if (L<=mid) s=query(ls,l,mid,L,R);
     96   if (R>mid) s+=query(rs,mid+1,r,L,R);
     97   s%=phi[0];
     98   return s;
     99 }
    100 int main()
    101 {lol p;
    102   int l,r,i;
    103   int opt;
    104   cin>>n>>m>>p>>c;
    105   for (i=1;i<=n;i++)
    106     scanf("%d",&a[i]);
    107   pre(p);
    108   build(1,1,n);
    109   for (i=1;i<=m;i++)
    110     {
    111       scanf("%d%d%d",&opt,&l,&r);
    112       if (opt==1)
    113     {
    114       ans=query(1,1,n,l,r);
    115       printf("%d
    ",ans);
    116     }
    117       else
    118     {
    119       update(1,1,n,l,r);
    120     }
    121     }
    122 }
    View Code1
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 typedef long long lol;
      8 int n,m;
      9 int c,ans;
     10 int sum[400001],a[100001],pw1[51][10001],pw2[51][10001];
     11 int phi[10001],cnt,ts[400001];
     12 bool ok1[51][10001],ok2[51][10001];
     13 int get_phi(int N)
     14 {int i;
     15   int res=N,x=N;
     16   for (i=2;i*i<=N;i++)
     17     {
     18       if (x%i) continue;
     19       res=res/i*(i-1);
     20       while (x%i==0) x/=i;
     21     }
     22   if (x!=1) res=res/x*(x-1);
     23   return res;
     24 }
     25 void pre(lol p)
     26 {
     27   phi[0]=p;cnt=0;
     28   while (p!=1)
     29     {
     30       int t=get_phi(p);
     31       phi[++cnt]=t;
     32       p=t;
     33     }
     34   phi[++cnt]=1;
     35 }
     36 int qpow(int x,int y,int p)
     37 {
     38   return (1ll*pw1[p][y%10000]*pw2[p][y/10000])%phi[p];
     39 }
     40 int cal(int x,int k)
     41 {
     42   int res=x,pre;
     43   bool ok=0;
     44   if (res>=phi[k]) ok=1;
     45   while (k)
     46     {
     47       if (ok) res=res%phi[k]+phi[k];
     48       pre=res;
     49       res=qpow(c,res,k-1);
     50       if (log(phi[k-1])/log(c)<=pre) ok=1;
     51       else ok=0;
     52       k--;
     53     }
     54   return res;
     55 }
     56 void build(int rt,int l,int r)
     57 {
     58   if (l==r)
     59     {
     60       sum[rt]=a[l]%phi[0];
     61       return;
     62     }
     63   int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1;
     64   build(ls,l,mid);
     65   build(rs,mid+1,r);
     66   sum[rt]=(sum[ls]+sum[rs])%phi[0];
     67 }
     68 void update(int rt,int l,int r,int L,int R)
     69 {
     70   if (ts[rt]>=cnt) return;
     71   if (l==r)
     72     {
     73       ts[rt]++;
     74       sum[rt]=cal(a[l],ts[rt]);
     75       return;
     76     }
     77   int mid=(l+r)>>1,ls=rt<<1,rs=rt<<1|1;
     78   if (L<=mid) update(ls,l,mid,L,R);
     79   if (R>mid) update(rs,mid+1,r,L,R);
     80   sum[rt]=(sum[ls]+sum[rs])%phi[0];
     81   ts[rt]=min(ts[ls],ts[rs]);
     82 }
     83 lol query(int rt,int l,int r,int L,int R)
     84 {
     85   if (l>=L&&r<=R)
     86     {
     87       return sum[rt];
     88     }
     89   int mid=(l+r)/2,ls=rt<<1,rs=rt<<1|1;
     90   lol s=0;
     91   if (L<=mid) s=query(ls,l,mid,L,R);
     92   if (R>mid) s+=query(rs,mid+1,r,L,R);
     93   s%=phi[0];
     94   return s;
     95 }
     96 int main()
     97 {lol p;
     98   int l,r,i,j;
     99   int opt;
    100   cin>>n>>m>>p>>c;
    101   for (i=1;i<=n;i++)
    102     scanf("%d",&a[i]);
    103   pre(p);
    104   build(1,1,n);
    105   for (i=0;i<=cnt;i++)
    106     {
    107       pw1[i][0]=1;
    108       for (j=1;j<=10000;j++)
    109     {
    110       pw1[i][j]=1ll*pw1[i][j-1]*c%phi[i];
    111     }
    112       pw2[i][0]=1;
    113       for (j=1;j<=10000;j++)
    114     {
    115       pw2[i][j]=1ll*pw2[i][j-1]*pw1[i][10000]%phi[i];
    116     }
    117     }
    118   for (i=1;i<=m;i++)
    119     {
    120       scanf("%d%d%d",&opt,&l,&r);
    121       if (opt==1)
    122     {
    123       ans=query(1,1,n,l,r);
    124       printf("%d
    ",ans);
    125     }
    126       else
    127     {
    128       update(1,1,n,l,r);
    129     }
    130     }
    131 }
    View Code2
  • 相关阅读:
    [codeforces] 97B Superset || 平面分治
    [hdu] 5696 区间的价值 || 序列分治
    [zoj] 1937 [poj] 2248 Addition Chains || ID-DFS
    [poj] 2286 The Rotation Game || ID-DFS
    [codeforces] 25E Test || hash
    luogu P1196 银河英雄传说
    luogu P1357 花园
    luogu P1156 垃圾陷阱
    luogu P1127 词链
    luogu P1131 时态同步
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8304885.html
Copyright © 2011-2022 走看看