1. 程式人生 > >noip模擬賽 大芳的逆行板載

noip模擬賽 大芳的逆行板載

編號 pushd 數字 錯誤 實用 tar ring 說明 展開

題目背景

大芳有一個不太好的習慣:在車裏養青蛙。青蛙在一個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模擬賽 大芳的逆行板載