zoukankan      html  css  js  c++  java
  • 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
    ", query(1, n, 1, l, r, x));
        }
    
        return 0;
    }
  • 相关阅读:
    JUC基础(三):ConcurrentHashMap 锁分段机制
    JUC基础(二):原子变量 CAS算法
    JUC基础(一):volatile 关键字 内存可见性
    JAVA多线程(十):线程创建使用 (四)JDK5.0新增线程创建方式
    JAVA多线程(九):线程通信(二)线程的通信经典例题:生产者/消费者问题
    JAVA多线程(八):线程通信(一)线程的通信基础
    JAVA多线程(七):线程同步(三)线程的同步代码练习
    JAVA多线程(六):线程同步(二)线程的同步代码实现
    JAVA多线程(五):线程同步(一)线程的同步
    JAVA多线程(四):线程创建使用 (三)线程的生命周期
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7586979.html
Copyright © 2011-2022 走看看