bzoj4869

http://www.lydsy.com/JudgeOnline/problem.php?id=4869

终于A了。。。参考了下dalao的代码。。。

拓展欧几里得定理,改了几次就不变了,但是用的时候要在快速幂里判是不是要用。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int n, m, cnt;
ll p, c;
ll phi[N], table[N];
namespace seg // n^x = n^(x % phi[x] + phi[x])
{
    struct data {
        ll ans, mn;
    } tree[N << 2];
    inline ll getphi(ll x)
    {
        ll ret = x, lim = x;
        for(ll i = 2; i * i <= lim; ++i) if(x % i == 0)
        {
            ret = ret * (i - 1) / i;
            while(x % i == 0) x /= i;
        }
//      printf("ret=%d\n", ret);
        if(x > 1) ret = ret * (x - 1) / x;
        return ret;
    }
    inline ll power(ll x, ll t, ll p, bool &flag)
    {
        bool big = false;
        ll ret = 1;
        for(; t; t >>= 1)
        {
            if(t & 1)
            {
                ret = ret * x ;
                flag |= big | (ret >= p);
                ret %= p;
            }
            x = x * x; if(x >= p) big = true, x %= p;
        }
        return ret;
    }
    ll calc(ll x, int t)
    {
        if(x >= phi[t]) x = x % phi[t] + phi[t];
        for(int i = t - 1; i >= 0; --i)
        {
            bool flag = false;
            x = power(c, x, phi[i], flag);
            if(flag) x += phi[i];
        }
        return x % phi[0];
    }
    inline void build(int l, int r, int x)
    {
        if(l == r) {
            tree[x].ans = table[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, x << 1);
        build(mid + 1, r, x << 1 | 1);
        tree[x].ans = (tree[x << 1].ans
                     + tree[x << 1 | 1].ans) % phi[0];
    }
    inline void update(int l, int r, int x, int a, int b)
    { //如果这次的幂和上次一样就不变了
        if(tree[x].mn >= cnt) return;
        if(l > b || r < a) return;
        if(l == r)
        {
            ++tree[x].mn;
            tree[x].ans = calc(table[l], tree[x].mn);
            return;
        }
        int mid = (l + r) >> 1;
        update(l, mid, x << 1, a, b);
        update(mid + 1, r, x << 1 | 1, a, b);
        tree[x].mn = min(tree[x << 1].mn,
                         tree[x << 1 | 1].mn);
        tree[x].ans = (tree[x << 1].ans +
                       tree[x << 1 | 1].ans) % phi[0];
    }
    inline ll query(int l, int r, int x, int a, int b)
    {
        if(l > b || r < a) return 0;
        if(l >= a && r <= b) return tree[x].ans % phi[0];
        int mid = (l + r) >> 1, ret = 0;
        ret = (ret + query(l, mid, x << 1, a, b)) % phi[0];
        ret = (ret + query(mid + 1, r, x << 1 | 1, a, b)) % phi[0];
        return ret;
    }
} using namespace seg;
int main()
{
    scanf("%d%d%lld%lld", &n, &m, &p, &c);
    phi[0] = p;
    ll P = p;
    while(P != 1) phi[++cnt] = P = getphi(P);
    phi[++cnt] = 1;
    for(int i = 1; i <= n; ++i) scanf("%lld", &table[i]);
    build(1, n, 1);
    while(m--)
    {
        int opt, l, r; scanf("%d", &opt);
        if(opt == 0)
        {
            scanf("%d%d", &l, &r);
            update(1, n, 1, l, r);
        }
        if(opt == 1)
        {
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, n, 1, l, r));
        }
    }
    return 0;
}

时间: 2024-10-21 12:28:26

bzoj4869的相关文章

【BZOJ4869】相逢是问候(线段树,欧拉定理)

[BZOJ4869]相逢是问候(线段树,欧拉定理) 题面 BZOJ 题解 根据欧拉定理递归计算(类似上帝与集合的正确用法) 所以我们可以用线段树维护区间最少的被更新的多少次 如果超过了\(\varphi\)的限制 就不用再计算了 如果需要计算就每次暴力算 这样的复杂度\(O(nlog^2)\) #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<

bzoj4869 [Shoi2017]相逢是问候

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4869 [题解] 发现好像没有办法普通维护. 给小盆友们江数论的时候江过x^m mod p = x^(m mod phi(p)) mod p 发现一个数进行phi操作最多log次. 暴力就行啦qwq 注意就是phi的那个最后要补一个phi[++pn] = 1. 为什么呢?因为phi(1) = 1(展开到最后,还要多展开一层(!)) 那么就行啦! 复杂度不大会分析qwq 照理性分析可能是log

【BZOJ4869】相逢是问候 [线段树]

相逢是问候 Time Limit: 40 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是 输入的一个常数,也就是执行赋值

bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候

http://www.lydsy.com/JudgeOnline/problem.php?id=4869 欧拉降幂+线段树,每个数最多降log次,模数就会降为1 #include<cmath> #include<cstdio> #include<iostream> using namespace std; #define N 50001 int n,m,p,c; int a[N]; int sum[N<<2]; int tag[N<<2]; in

[BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)

4869: [Shoi2017]相逢是问候 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1313  Solved: 471[Submit][Status][Discuss] Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每

【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理

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因为 这个结果可能会很大,所以你只需要输出结

BZOJ 4868-4873 题解

BZOJ4868 每个结束位置的最优值很显然具有单调性,三分,再讨论一下就好了. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define FILE "exam" 5 #define up(i,j,n) for(int i=j;i<=n;i++) 6 #define db long double 7 #define pii pair<int,int>

东北育才10天大总结

老师们 Scanf的嗓门照例是最大的.恩. “我是山里的孩子……小的时候背书,整个山头都听得见……” 有一个哈师大附中的竞赛教练很……怎么说呢?接地气好了. Scanf说东北人很耿直,似乎确实是这样的.衡水的教练早就被遣返了…… “他啊,监考去了!” 虽然他不在,但还是不还手机.让衡水的人天天在电脑上颓废…… Scanf不在,你看我们就很老实.他到处“乱”玩,甚至跑到了国境线边,连火车票都忘了买,坐高铁去,乘绿皮火车回,路过长白山就去玩了一趟,结果暴风雪逼得他去吃“暴辣”的烤鱿鱼. “我看<三八

2017/07/25 杂题(完全不可做题(划去))选讲

先膜一发主讲人@Antileaf 真是核平的一天那--大脑已经被蹂躏的死去活来了-- cogs2421 简单的Treap 链接:http://cogs.pro/cogs/problem/problem.php?pid=2421 题意:什么都给你了,建出Treap,输出先序遍历顺序. 实际上只是用了Treap的原则建树--先按照数值大小排序,然后按照建立笛卡尔树方法,维护单调栈,最大的全扔到右儿子去即可. 1 #include<iostream> 2 #include<cstdio>