I
题意
给定一个字符串 s s 和一个字符,将所有的 |(int)(L−s[i])| | ( i n t ) ( L − s [ i ] ) | 转化为一个两位数后,按顺序拼接在一起,问,这个拼接而成的新序列,去掉前导0后的长度是多少
思路
按照模拟去实现一下过程就可以,可以计算前导零的个数,就不用算出所有的值了,现给出一种纯模拟的写法
代码
int a[maxn];
char s[maxn], ch;
int main()
{
int T;
sd(T);
while(T--){
int n, now = 0, ans = 1;
scanf("%d %c", &n, &ch);
if(n==0) {
puts("1");
continue;
}
ss(s);
rep(i, 0, n){
int t = abs((int)(ch-s[i]));
a[now++] = t/10;
a[now++] = t%10;
}
rep(i, 0, 2*n){
if(a[i] != 0) {
ans = 2*n-i;
break;
}
}
pd(ans);
}
return 0;
}
H
题意
给出一个长度为
n
n
的序列, 次询问:
1 l r
1
l
r
询问
a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r]
a
[
l
]
×
L
+
a
[
l
+
1
]
×
(
L
−
1
)
+
⋯
+
a
[
r
−
1
]
×
2
+
a
[
r
]
,其中
L
L
是区间的长度。
2 x k
2
x
k
表示将序列中第
x
x
个数设置为
思路
题目是一眼看过去就知道是线段树的题,那么就变成了我们怎么往线段树上去考虑了。
从线段树的思想入手,线段树能解决区间问题的原因是,我们可以对区间维护的值进行合并,而这样的一个类似梯度的求和,我们相当于维护了两个区间的和
sum
s
u
m
, 区间的”梯度和”(所求部分)
ans
a
n
s
, 以及区间的长度
len
l
e
n
, 用线段树来表示的话,我们可以得到这样一个维护方程
代码
struct Node{
int l, r, len;
ll sum, ans;
}tree[maxn<<2]; //开四倍空间
ll num[maxn]; //数值数组
void build(int i, int l, int r){
tree[i].l = l;
tree[i].r = r;
tree[i].len = (r-l+1);
if(l == r){
tree[i].sum = num[l];
tree[i].ans = num[l];
return ;
}
int mid = (l+r)>>1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r); //子树建树后更新特征值
tree[i].sum = tree[i<<1].sum + tree[i<<1|1].sum;
tree[i].ans = tree[i<<1].ans + tree[i<<1|1].ans + tree[i<<1].sum*tree[i<<1|1].len;
return ;
}
void setx(int i, int x, int k){ // num[x] = k
if(tree[i].l == tree[i].r) {
tree[i].sum = k;
tree[i].ans = k;
return ;
}
int mid = (tree[i].l+tree[i].r)>>1;
if(x <= mid) setx(i<<1, x, k);
else setx(i<<1|1, x, k);
tree[i].sum = tree[i<<1].sum + tree[i<<1|1].sum;
tree[i].ans = tree[i<<1].ans + tree[i<<1|1].ans + tree[i<<1].sum*tree[i<<1|1].len;
}
ll querys(int i, int l, int r) {
if(tree[i].l==l && tree[i].r==r)
return tree[i].sum;
int mid = (tree[i].l+tree[i].r)>>1;
if(mid >= r)
return querys(i<<1, l, r);
else if(mid < l)
return querys(i<<1|1, l, r);
else
return querys(i<<1, l, mid) + querys(i<<1|1, mid+1, r) ;
}
ll querya(int i, int l, int r) {
if(tree[i].l==l && tree[i].r==r)
return tree[i].ans;
int mid = (tree[i].l+tree[i].r)>>1;
if(mid >= r)
return querya(i<<1, l, r);
else if(mid < l)
return querya(i<<1|1, l, r);
else
return querya(i<<1, l, mid) + querya(i<<1|1, mid+1, r) + querys(i<<1, l, mid)*(r-mid);
}
int main() {
int n, q;
sdd(n, q);
rep(i, 1, n+1)
sld(num[i]);
build(1, 1, n);
rep(i, 0, q) {
int op, l, r;
sddd(op, l, r);
if(op == 1){
printf("%lld\n", querya(1, l, r));
}
else {
setx(1, l, r);
}
}
return 0;
}