链接:
题意:
给定数组b,数组a一开始全部都是0,对数组a可以每次选定一个长为k的区间,区间加上一个公差为1,首项为1的等差数列。问最少操作几次,可以使数组a[i]>=b[i]。
做法:
线段树维护区间加等差数列。两个懒标记,一个首项,一个公差。
从数组a最后一个<b的数开始,以他为右端点开始区间加,这样一定最优。
只一个懒标记的是线段树维护差分数组,区间加等差数列,变成差分数组L加首项,L+1~R区间加公差,R+1-=刚刚加的值。
这里放上一道板子题的代码,区间加等差数列。
链接:洛谷-P1438
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5, mod = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
int a[N], b[N];
int inv = mod / 2 + 1;
struct node
{
int l, r;
int val;
int a1, d;
#define l(x) tree[x].l
#define r(x) tree[x].r
} tree[N * 4];
void build(int p, int l, int r)
{
tree[p].l = l, tree[p].r = r;
if (l >= r)
{
tree[p].val = a[l];
return;
}
int mid = (l + r) >> 1;
int chl = p * 2, chr = p * 2 + 1;
build(chl, l, mid);
build(chr, mid + 1, r);
tree[p].val = (tree[chl].val + tree[chr].val);
}
int calc(int a1, int d, int l, int r)
{
int fir = a1, en = a1 + (r - l) * d;
return (fir + en) * (r - l + 1) / 2;
}
void pushdown(int p)
{
if (tree[p].a1 || tree[p].d)
{
int chl = p * 2, chr = p * 2 + 1;
tree[chl].val = (tree[chl].val + calc(tree[p].a1, tree[p].d, l(chl), r(chl)));
tree[chl].a1 = (tree[chl].a1 + tree[p].a1);
tree[chl].d = (tree[chl].d + tree[p].d);
int k = (tree[p].a1 + (l(chr) - l(chl)) * tree[p].d);
tree[chr].val = (tree[chr].val + calc(k, tree[p].d, l(chr), r(chr)));
tree[chr].a1 = (tree[chr].a1 + k);
tree[chr].d = (tree[chr].d + tree[p].d);
// sum[ls]=(1ll*sum[ls]+cal(l,mid,lx[cur],ld[cur]) )%mod;
// lx[ls]=(1ll*lx[ls]+lx[cur])%mod;
// ld[ls]=(1ll*ld[ls]+ld[cur])%mod;
// lx[cur]=( 1ll*lx[cur]+1ll*(mid+1-l)*ld[cur]%mod )%mod;
// sum[rs]=(1ll*sum[rs]+cal(mid+1,r,lx[cur],ld[cur]) )%mod;
// lx[rs]=(1ll*lx[rs]+lx[cur])%mod;
// ld[rs]=(1ll*ld[rs]+ld[cur])%mod;
// lx[cur]=ld[cur]=0;
tree[p].a1 = tree[p].d = 0;
}
}
void up(int p, int l, int r, int a1, int d)
{
if (l <= l(p) && r >= r(p))
{
int fir = (a1 + (l(p) - l) * d);
int en = (a1 + (r(p) - l) * d);
tree[p].val = (tree[p].val + (fir + en) * (r(p) - l(p) + 1) / 2);
// tree[p].val %= mod;
tree[p].a1 = (tree[p].a1 + fir);
tree[p].d = (tree[p].d + d);
return;
}
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
int chl = p * 2, chr = p * 2 + 1;
if (l <= mid)
up(chl, l, r, a1, d);
if (mid < r)
up(chr, l, r, a1, d);
tree[p].val = (tree[chl].val + tree[chr].val);
}
int que(int p, int l, int r)
{
if (l <= l(p) && r >= r(p))
{
return tree[p].val;
}
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
int chl = p * 2, chr = p * 2 + 1;
int ret = 0;
if (l <= mid)
ret = (ret + que(chl, l, r));
if (mid < r)
ret = (ret + que(chr, l, r));
return ret;
}
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
build(1, 1, n);
while(m--)
{
int op;
cin >> op;
if (op == 2) {
int x;
cin >> x;
printf("%lld\n", que(1, x, x));
}
else
{
int l, r, a1, d;
scanf("%lld%lld%lld%lld", &l, &r, &a1, &d);
up(1, l, r, a1, d);
}
}
}
signed main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
int tt = 1;
// cin >> tt;
while (tt--)
solve();
return 0;
}
牛牛的等差数列
牛客还有一题类似的,稍微不同的是输出,区间和要输出对3~25中的某个质数取模结果。
直接定义模数为3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;还要用到2的逆元,因为这个模数并不是质数,所以费马小定理不适用,inv = mod / 2 + 1;这才是2的逆元。
因为n % num % d == n % d,当d是num的因子时。这样这题也就好做了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5, mod = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
int a[N], b[N];
int inv = mod / 2 + 1;
struct node
{
int l, r;
int val;
int a1, d;
#define l(x) tree[x].l
#define r(x) tree[x].r
} tree[N * 4];
void build(int p, int l, int r)
{
tree[p].l = l, tree[p].r = r;
if (l >= r) {
tree[p].val = a[l]%mod;
return;
}
int mid = (l + r) >> 1;
int chl = p * 2, chr = p * 2 + 1;
build(chl, l, mid);
build(chr, mid + 1, r);
tree[p].val = (tree[chl].val + tree[chr].val) % mod;
}
int calc(int a1, int d, int l, int r)
{
int fir = a1, en = a1 + (r - l) * d;
en %= mod;
return (fir + en) * (r - l + 1) % mod * inv % mod;
}
void pushdown(int p)
{
if (tree[p].a1 || tree[p].d) {
int chl = p * 2, chr = p * 2 + 1;
tree[chl].val = (tree[chl].val + calc(tree[p].a1, tree[p].d, l(chl), r(chl) ) ) % mod;
tree[chl].a1 = (tree[chl].a1 + tree[p].a1) % mod;
tree[chl].d = (tree[chl].d + tree[p].d) % mod;
int k = (tree[p].a1 + (l(chr) - l(chl)) * tree[p].d % mod) % mod;
tree[chr].val = (tree[chr].val + calc(k, tree[p].d, l(chr), r(chr) ) ) % mod;
tree[chr].a1 = (tree[chr].a1 + k) % mod;
tree[chr].d = (tree[chr].d + tree[p].d) % mod;
// sum[ls]=(1ll*sum[ls]+cal(l,mid,lx[cur],ld[cur]) )%mod;
// lx[ls]=(1ll*lx[ls]+lx[cur])%mod;
// ld[ls]=(1ll*ld[ls]+ld[cur])%mod;
// lx[cur]=( 1ll*lx[cur]+1ll*(mid+1-l)*ld[cur]%mod )%mod;
// sum[rs]=(1ll*sum[rs]+cal(mid+1,r,lx[cur],ld[cur]) )%mod;
// lx[rs]=(1ll*lx[rs]+lx[cur])%mod;
// ld[rs]=(1ll*ld[rs]+ld[cur])%mod;
// lx[cur]=ld[cur]=0;
tree[p].a1 = tree[p].d = 0;
}
}
void up(int p, int l, int r, int a1, int d)
{
if (l <= l(p) && r >= r(p)) {
int fir = (a1 + (l(p) - l) * d % mod)%mod;
int en = (a1 + (r(p) - l) * d % mod)%mod;
tree[p].val = (tree[p].val+(fir + en) * (r(p) - l(p) + 1)%mod*inv%mod)%mod;
// tree[p].val %= mod;
tree[p].a1 = (tree[p].a1 + fir) % mod;
tree[p].d = (tree[p].d + d) % mod;
return;
}
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
int chl = p * 2, chr = p * 2 + 1;
if (l <= mid) up(chl, l, r, a1, d);
if (mid < r) up(chr, l, r, a1, d);
tree[p].val = (tree[chl].val + tree[chr].val)%mod;
}
int que(int p, int l, int r)
{
if (l <= l(p) && r >= r(p)) {
return tree[p].val;
}
pushdown(p);
int mid = (l(p) + r(p)) >> 1;
int chl = p * 2, chr = p * 2 + 1;
int ret = 0;
if (l <= mid) ret =( ret + que(chl, l, r))%mod;
if (mid < r) ret = (ret+que(chr, l, r))%mod;
return ret;
}
int qpow (int x, int n)
{
int ret = 1;
while (n) {
if (n & 1) ret = ret * x % mod;
x = x* x % mod;
n >>= 1;
}
return ret;
}
void solve()
{
// inv = qpow(2, mod - 2);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
build(1, 1, n);
int m;
cin >> m;
while(m--)
{
int op;
cin >> op;
if (op == 2) {
int l, r, mod;
scanf("%lld%lld%lld", &l, &r, &mod);
printf("%lld\n", que(1, l, r) % mod);
}
else
{
int l, r, a1, d;
scanf("%lld%lld%lld%lld", &l, &r, &a1, &d);
up(1, l, r, a1 % mod, d % mod);
}
}
}
signed main()
{
int tt = 1;
// cin >> tt;
while (tt--) solve();
return 0;
}