版权声明:本文为博主原创文章,未经博主允许不得转载。 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函数的返回值, 输出
。
题目思路:
首先观察这个SOD函数
将x展开 由
, 可以直觉看出是做了个模15操作, 即
然后就知道其返回值实际上遵循
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;
}