zoukankan      html  css  js  c++  java
  • bzoj 4597 随机序列

    Description

    你的面前有N个数排成一行。分别为A1, A2, … , An。你打算在每相邻的两个 Ai和 Ai+1 间都插入一个加号或者
    减号或者乘号。那么一共有 3^(n-1) 种可能的表达式。你对所有可能的表达式的值的和非常感兴趣。但这毕竟太
    简单了,所以你还打算支持一个修改操作,可以修改某个Ai 的值。你能够编写一个程序对每个修改都输出修改完
    之后所有可能表达式的和吗?注意,修改是永久的,也就是说每次修改都是在上一次修改的基础上进行, 而不是
    在最初的表达式上进行。

    Input

    第一行包含 2 个正整数 N 和 Q,为数的个数和询问的个数。
    接下来一行 n 个非负整数,依次表示a1,a2...an
    在接下来 Q 行,其中第 ?? 行两个非负整数Ti 和Vi,表示要将 Ati 修改为 Vi。其中 1 ≤ Ti ≤ N。
    保证对于 1 ≤ J ≤ N, 1 ≤ i≤ Q,都有 Aj,Vi ≤ 10^4。
    N,Q<=100000,本题仅有三组数据

    Output

    输出共 Q 行,其中第 i 行表示第 i 个询问之后所有可能表达式的和,对10^9 + 7 取模。
     
    题解
    首先想到+、-号会导致后面的所有结果相互抵消。所以对答案有贡献的是前面一直是连乘的部分。即第一个非乘号的前面部分
    所以我们只需要维护前缀积,修改的时候线段树区间修改,先预处理逆元就可以做了
    我认为这道题最关键的地方就是+、-号相互抵消,一下子简化了问题。一开始想是否有规律,真实太蠢了
     
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 #define maxn 100020
     7 
     8 typedef long long ll;
     9 const ll mod = 1e9 + 7;
    10 struct node{
    11     int ls,rs;
    12     ll sum,mul;
    13 }sgt[maxn * 4];
    14 ll inv[maxn],fac[maxn],sum[maxn],pow[maxn];
    15 int n,a[maxn],q,rt,tot;
    16 
    17 inline ll power(ll x,int y){
    18     ll res = 1;
    19     while ( y ){
    20         if ( y & 1 ) res = res * x % mod;
    21         x = x * x % mod;
    22         y >>= 1;
    23     }
    24     return res % mod;
    25 }
    26 void init(){
    27     for (int i = 1 ; i <= 10000 ; i++) inv[i] = power(i,mod - 2);
    28     pow[0] = 1;
    29     for (int i = 1 ; i <= 100000 ; i++) pow[i] = pow[i - 1] * 3ll % mod;
    30 }
    31 inline void update(int x){
    32     sgt[x].sum = sgt[sgt[x].ls].sum + sgt[sgt[x].rs].sum;
    33     if ( sgt[x].sum >= mod ) sgt[x].sum -= mod;
    34 }
    35 void build(int &x,int l,int r){
    36     x = ++tot;
    37     sgt[x].mul = 1;
    38     if ( l == r ){
    39         if ( l == n ) sgt[x].sum = sum[l];
    40         else sgt[x].sum = sum[l] * pow[n - l - 1] * 2ll % mod;
    41         return;
    42     }
    43     int mid = (l + r) >> 1;
    44     build(sgt[x].ls,l,mid);
    45     build(sgt[x].rs,mid + 1,r);
    46     update(x);
    47 }
    48 inline void mul(int x,ll d){
    49     sgt[x].sum = sgt[x].sum * (ll)d % mod;
    50     sgt[x].mul = sgt[x].mul * (ll)d % mod; 
    51 }
    52 inline void pushdown(int x){
    53     if ( sgt[x].mul != 1 ){
    54         mul(sgt[x].ls,sgt[x].mul);
    55         mul(sgt[x].rs,sgt[x].mul);
    56         sgt[x].mul = 1;
    57     }
    58 }
    59 void modify(int x,int l,int r,int ls,int rs,ll d){
    60     if ( ls <= l && rs >= r ){
    61         mul(x,d);
    62         return;
    63     }
    64     pushdown(x);
    65     int mid = (l + r) >> 1;
    66     if ( ls <= mid ) modify(sgt[x].ls,l,mid,ls,rs,d);
    67     if ( rs > mid ) modify(sgt[x].rs,mid + 1,r,ls,rs,d);
    68     update(x);
    69 }
    70 int main(){
    71     //freopen("input.txt","r",stdin);
    72     scanf("%d %d",&n,&q);
    73     init();
    74     for (int i = 1 ; i <= n ; i++){
    75         scanf("%d",&a[i]);
    76     }
    77     sum[0] = 1;
    78     for (int i = 1 ; i <= n ; i++) sum[i] = a[i] * sum[i - 1] % mod;
    79     build(rt,1,n);
    80     while ( q-- ){
    81         int id,v;
    82         scanf("%d %d",&id,&v);
    83         modify(rt,1,n,id,n,inv[a[id]]);
    84         modify(rt,1,n,id,n,v);
    85         a[id] = v;
    86         printf("%lld
    ",sgt[rt].sum);
    87     }
    88     return 0;
    89 }
  • 相关阅读:
    String.Split()函数
    Java的位运算符具体解释实例——与(&amp;)、非(~)、或(|)、异或(^)
    开机黑屏 仅仅显示鼠标 电脑黑屏 仅仅有鼠标 移动 [已成功解决]
    Java中Scanner的使用方法
    C++经典面试题
    人脸识别算法初次了解
    ShareSDK的简化压缩和使用样例
    hdu 1316 How Many Fibs? (模拟高精度)
    AABB包围盒、OBB包围盒、包围球的比較
    Windows 7系统安装MySQL5.5.21图解
  • 原文地址:https://www.cnblogs.com/zqq123/p/5505857.html
Copyright © 2011-2022 走看看