您的位置:首页 > 其它

HDU 5238 Calculator(中国剩余定理+线段树)

2015-06-17 09:19 337 查看

题意:

有加,乘,次方3种运算,初始值为x,给定运算式。

现在有2种操作:

第一种:告诉你x的值,求答案模29393。

第二种:更改某个位置的运算。

解析:

线段树维护值域的问题,但是那个操作并不能简单的合并,因为值域还是很大的数组开不下,所以我们得另寻他法。

可以发觉29393并不是质数,29393 = 7×13×17×19。


设:

t1=ans%7t1 = ans\%7,t2=ans%13t2=ans\%13,t3=ans%17t3=ans\%17,t4=ans%19t4=ans\%19


那么问题的解就是模方程组

⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪x≡t1(mod)7x≡t2(mod)13x≡t3(mod)17x≡t4(mod)19\left\{
\begin{aligned}
x≡t1(mod)7 \\
x≡t2(mod)13 \\
x≡t3(mod)17\\
x≡t4(mod)19
\end{aligned}
\right.


所以我们对其中因子做线段树,线段树只需维护对于每个小于质因子的数经过这个区间答案是几即可,最后利用中国剩余定理对答案进行合并。

mymy codecode

[code]#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
using namespace std;

const int MAXN = 50005;
const int MOD = 29393;
int factor[] = {7, 13, 17, 19};

//modpow
//------------------------------------------
int modpow(int a, int k, int p) {
    int c = 1;
    while(k) {
        if(k & 1) c = (c*a) % p;
        a = (a*a)%p;
        k >>= 1;
    }
    return c;
}

//segment tree
//------------------------------------------
struct Oper {
    char ch; 
    int val;

    inline void read() {
        char cmd[10];
        scanf("%s", cmd);
        ch = cmd[0];
        sscanf(cmd+1, "%d", &val);
    }

    inline int cal(int x, int p) {
        int ret = 0;
        switch(ch) {
        case '+': ret = (x + val) % p;
            break;
        case '*': ret = (x * val) % p;
            break;
        case '^': ret = modpow(x, val, p);
            break;
        }
        return ret;
    }
} op[MAXN];

int pos; //修改的位置
struct Tree {
    int mod;
    int value[MAXN<<2][20];

    inline void pushUp(int o) { //左边维护的值,传到右边维护
        for(int i = 0; i < mod; i++) {
            value[o][i] = value[rs][value[ls][i]];
        }
    }

    void build(int o, int L, int R) {
        if(L == R) {
            for(int i = 0; i < mod; i++)
                value[o][i] = op[L].cal(i, mod);
            return ;
        }
        int M = (L+R)/2;
        build(ls, L, M);
        build(rs, M+1, R);
        pushUp(o);
    }

    void modify(int o, int L, int R) {
        if(L == R) {
            for(int i = 0; i < mod; i++)
                value[o][i] = op[L].cal(i, mod);
            return ;
        }
        int M = (L+R)/2;
        if(pos <= M) modify(ls, L, M);
        else modify(rs, M+1, R);
        pushUp(o);
    }
} tree[4];
//------------------------------------------

//mod rule
//------------------------------------------
int exgcd (int a, int b, int &x, int &y) {
    if ( !b ) {
        x = 1, y = 0;
        return a;
    }
    int ans = exgcd ( b , a % b , y , x );
    y -= a / b * x;
    return ans;
}

int calc(int val) {
    int ans = 0;
    for (int i = 0 ; i < 4 ; i++) {
        int tmp = MOD / factor[i] , x , y;
        exgcd(tmp , factor[i] , x , y);
        ans = (ans + tree[i].value[1][val % factor[i]] * tmp * (x % factor[i]) ) % MOD ;
    }
    return (ans+MOD) % MOD;
}
//------------------------------------------

int n, m;
int main() {
    //freopen("in.txt", "r", stdin);
    int T, cas = 1;
    scanf("%d", &T);
    while(T--) {
        printf("Case #%d:\n", cas++);
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            op[i].read();
        for(int i = 0; i < 4; i++) {
            tree[i].mod = factor[i];
            tree[i].build(1, 1, n);
        }
        int choice, x;
        while(m--) {
            scanf("%d", &choice);
            if(choice == 1) {
                scanf("%d", &x);
                printf("%d\n", calc(x));        
            }else {
                scanf("%d", &pos);
                op[pos].read();
                for(int i = 0; i < 4; i++)
                    tree[i].modify(1, 1, n);
            }
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: