noip模拟赛 大芳的逆行板载

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip模拟赛 大芳的逆行板载相关的知识,希望对你有一定的参考价值。

题目背景

大芳有一个不太好的习惯:在车里养青蛙。青蛙在一个n厘米(11n毫米s)的Van♂杆子上跳来跳去。她时常盯着青蛙看,以至于突然逆行不得不开始躲交叉弹。有一天他突发奇想,在杆子上每1厘米为一个单位,瞎涂上了墨水,并且使用mOgic,使青蛙跳过之处墨水浓度增加x。当然,他还会闲着无聊滴几滴墨水再涂♂抹均匀。

他现在无时无刻都想知道,第l厘米到第r厘米墨水的浓度是多少?

哦不!等等,他现在找到了一个计算器,可以输入几个数字与x,计算他们的x次幂和,所以。。。他想知道的是第l厘米到第r厘米墨水的浓度的x次幂和是多少?

题目描述

大芳有3种舰长技能骚操作

  1. 续:把青蛙放到第l厘米处,戳青蛙使其跳至r。效果:第l厘米至第r厘米墨水浓度增加x

  2. 抚♂摸:擦干杆子某一部分,重新滴加墨水并抹匀。效果:使第l厘米至第r厘米墨水浓度都变成x

最后一种是:

  1. 压线逆行,将车流看做⑨弹幕找安定点,掏出计算器,大喊板载后计算:

第l厘米至第r厘米墨水浓度的x次幂和是几何?记得答案要

1000000007

输入输出格式

输入格式:

 

第一行n和m,表示杆子长n厘米,大芳要进行m次骚操作。

第二行n个数字,表示初始墨水浓度。第i个数字为第i厘米墨水浓度

接下来每行4个数字,依次为:操作编号(1、2或3),l,r,x

 

输出格式:

 

每次进行3操作,输出一行表示答案

记得模1000000007

 

输入输出样例

输入样例#1:
5 5
19844 14611 26475 4488 6967 
2 1 3 15627
2 1 2 30113
2 3 5 14686
2 5 5 32623
3 1 2 8
输出样例#1:
466266421

说明

技术分享

 

分析:比较好的一道线段树的题,在细节处理方面收获了很多.

      暴力可以拿到30分,如果会一点线段树的基本操作应该是可以拿到60分的,想要拿满分关键在于k的处理.

      我们保存每个区间的i次幂和,如果是区间覆盖就很好办,幂*区间长度;如果是区间加就有点麻烦,要用到二项式定理来展开.比较麻烦,手推一下就出来了.同时要打两个标记,一个是覆盖标记,一个是累加标记,覆盖标记要在累加标记之前判断,并且会使累加标记变成0.

      如果在pushdown中写向子区间的更改操作代码就会比较繁琐,为了精简代码,我们可以另写一个函数来下传标记和更改子区间,这是一个非常实用的技巧.

      本题的模数比较大,如果直接上int的话一般而言是不会有问题的,但是当两数相乘的时候可能会爆int,所以临时转换成long long然后取模.

我以前是喜欢把不同的量放在不同的数组里写,今天用了一下struct,感觉放在结构体里写会更加直观工整.犯了一个最脑残的错误:逻辑判断弄错了,每次在操作1的时候我都会输出一次,导致过了样例然而所有点全WA.

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 200010, mod = 1000000007;

int n, m,k = 10,c[20][20],a[maxn];

struct node
{
    int l, r,v,ad,st;
    int p[11];
}e[maxn << 1];

void pushup(int o)
{
    for (int i = 0; i <= k; i++)
        e[o].p[i] = (e[o * 2].p[i] + e[o * 2 + 1].p[i]) % mod;
}

void sett(int o, int v)
{
    int res = 1;
    for (int i = 0; i <= k; i++)
    {
        e[o].p[i] = 1LL*res*(e[o].r - e[o].l + 1) % mod;
        res = 1LL*res * v % mod;
    }
    e[o].ad = 0;
    e[o].st = v;
}

void addd(int o, int v)
{
    for (int i = k; i >= 0; i--)
    {
        int res = 1, t = 0;
        for (int j = i; j >= 0; j--)
        {
            t = (t + 1LL * e[o].p[j] *c[i][j] % mod * res) % mod;
            res = 1LL * res * v % mod;
        }
        e[o].p[i] = t;
    }
    e[o].ad = (e[o].ad + v) % mod;
}

void pushdown(int o)
{
    if (e[o].st != -1)
    {
        sett(o * 2, e[o].st);
        sett(o * 2 + 1, e[o].st);
        e[o].st = -1;
    }
    if (e[o].ad)
    {
        addd(o * 2, e[o].ad);
        addd(o * 2 + 1, e[o].ad);
        e[o].ad = 0;
    }
}

void build(int l, int r, int o)
{
    e[o].l = l;
    e[o].r = r;
    e[o].st = -1;
    e[o].ad = 0;
    if (l == r)
    {
        e[o].p[0] = 1;
        for (int i = 1; i <= k; i++)
            e[o].p[i] = 1LL * e[o].p[i - 1] * a[l] % mod;
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, o * 2);
    build(mid + 1, r, o * 2 + 1);
    pushup(o);
}

void add(int l, int r, int o, int x, int y, int v)
{
    if (x <= l && r <= y)
    {
        addd(o,v);
        return;
    }
    pushdown(o);
    int mid = (l + r) >> 1;
    if (x <= mid)
        add(l, mid, o * 2, x, y, v);
    if (y > mid)
        add(mid + 1, r, o * 2 + 1, x, y, v);
    pushup(o);
}

void update(int l, int r, int o, int x, int y, int v)
{
    if (x <= l && r <= y)
    {
        sett(o, v);
        return;
    }
    pushdown(o);
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(l, mid, o * 2, x, y, v);
    if (y > mid)
        update(mid + 1, r, o * 2 + 1, x, y, v);
    pushup(o);
}

int query(int l, int r, int o, int x, int y, int v)
{
    if (x <= l && r <= y)
        return e[o].p[v];
    pushdown(o);
    int mid = (l + r) >> 1, sum = 0;
    if (x <= mid)
        sum = (sum + query(l, mid, o * 2, x, y, v)) % mod;
    if (y > mid)
        sum = (sum + query(mid + 1, r, o * 2 + 1, x, y, v)) % mod;
    return sum;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    build(1, n, 1);
    c[0][0] = 1;
    for (int i = 1; i <= k; i++)
    { 
        c[i][0] = 1;
        for (int j = 1; j <= i; j++)
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
    for (int i = 1; i <= m; i++)
    {
        int op, l, r, x;
        scanf("%d%d%d%d", &op, &l, &r, &x);
        if (op == 1)
            add(1, n, 1, l, r, x);
        if (op == 2)
            update(1, n, 1, l, r, x);
        if (op == 3)
            printf("%d\\n", query(1, n, 1, l, r, x));
    }

    return 0;
}

 




以上是关于noip模拟赛 大芳的逆行板载的主要内容,如果未能解决你的问题,请参考以下文章

NOIp模拟赛binary

NOIP模拟赛16

抗疫逆行者HTML网页作业 感动人物网页代码成品 最美逆行者网页模板 致敬疫情感动人物网页设计制作

NOIp模拟赛value

2017 10.25 NOIP模拟赛

ztz11的noip模拟赛T3:评分系统