D. Progressions Covering

链接:

D. Progressions Covering

题意:

给定数组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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值