[Nowcoder 2018ACM多校第三场F] Sum of Digit

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/81238942

题目大意:
定义函数SOD(x):
if (x < 16) return x;
return SOD(sum of the digits of x (base 16))
然后给你一个16进制的字符串S, 有Q组询问。 1 pos c, 表示把第pos位上的数字替换成c。 2 l r, 询问有区间[l,r]内所有可能子序列构成的数字的SOD函数的返回值, 输出 ( n u m b e r o f o u t p u t s b e i n g i ) 1021 i m o d ( 10 9 + 7 )

题目思路:
首先观察这个SOD函数
将x展开 由 x i 16 i => x i , 可以直觉看出是做了个模15操作, 即
x i 16 i => x i 1 i
然后就知道其返回值实际上遵循
if (x == 0) return 0;
else if (x % 15 == 0) return 15;
else return x % 15;
所以我们用线段树维护每个区间, 返回值为0~15的个数, 区间合并的时候, 枚举左右区间的答案取值, 合并即可。

Code:

#include <map>
#include <set>
#include <map>
#include <bitset>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

#define ll long long
#define db double
#define pw(x) ((x) * (x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define ls (x << 1)
#define rs ((x << 1) | 1)
#define mid ((l + r) >> 1)

using namespace std;

const int N = (int)1e5 + 10;
const int mo = (int) 1e9 + 7;

int n, q; char str[N]; ll pw[16];
struct Nd{
    ll v[20];
    Nd operator+(const Nd &_){
        Nd ret;
        memset(ret.v, 0, sizeof(ret.v));
        for (int i = 0; i < 16; i ++){
            for (int j = 0; j < 16; j ++){
                int c;
                if (i == 0 && j == 0) c = 0;
                else if ((i + j) % 15 == 0) c = 15;
                else c  = (i + j) % 15;
                (ret.v[c] +=  v[i] * _.v[j] % mo) %= mo;
            }
            (ret.v[i] += v[i]) %= mo;
            (ret.v[i] += _.v[i]) %= mo; 
        }
        return ret;
    }
    ll ans(){
        ll ret = 0;
        for (int i = 0; i < 16; i ++){
            //printf("%lld ", v[i]);
            (ret += v[i] * pw[i] % mo) %= mo;
        }
        return ret;
    }
}nd[N << 1];

void build(int x, int l, int r){
    if (l == r){
        int c;
        if (str[l] <= '9' && str[l] >= '0') c = str[l] - '0';
        else c = str[l] - 'A' + 10;
        nd[x].v[c] = 1;
        return;
    }

    build(ls, l, mid);
    build(rs, mid + 1, r);
    nd[x] = nd[ls] + nd[rs];
}

void modf(int x, int l, int r, int pos, int c){
    if (l == r){
        memset(nd[x].v, 0, sizeof(nd[x].v));
        nd[x].v[c] = 1;
        return;
    }

    if (pos <= mid) modf(ls, l, mid, pos, c);
    else modf(rs, mid + 1, r, pos, c);
    nd[x] = nd[ls] + nd[rs];
}

Nd query(int x, int l, int r, int L, int R){
    if (l == L && r == R) return nd[x];
    if (R <= mid) return query(ls, l, mid, L, R);
    if (L > mid) return query(rs, mid + 1, r, L, R);
    return query(ls, l, mid, L, mid) + query(rs, mid + 1, r, mid + 1, R);
}


int main(){

    pw[0] = 1;
    for (int i = 1; i < 16; i ++)
        pw[i] = pw[i - 1] * 1021 % mo;

    scanf("%d %d\n", &n, &q);
    scanf("%s\n", str + 1);
    build(1, 1, n);

    int opt, l, r; char c; int pos;
    while (q --){
        scanf("%d ", &opt);
        if (opt == 1){
            scanf("%d %c\n", &pos, &c);
            if (c <= '9' && c >= '0') c -= '0';
            else c = c - 'A' + 10;
            modf(1, 1, n, pos, (int)c);
        }
        else{
            scanf("%d %d\n", &l, &r);
            printf("%lld\n", query(1, 1, n, l, r).ans());
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013578420/article/details/81238942