首页 > 其他分享 >LG4868 Preprefix sum 题解

LG4868 Preprefix sum 题解

时间:2023-07-20 19:44:07浏览次数:69  
标签:limits int 题解 sum 查询 cdot Preprefix sim

壹、题目大意

给出长度为 \(n\) 的序列 \(a_1 \sim a_n\),设 \(S_i = \sum\limits_{j=1}^i a_j\),有两种操作

可以给定 \(i\) 和 \(x\),使得 \(a_i = x\),也可以给定 \(i\),查询 \(\sum\limits_{j=1}^i S_j\) 的值

\(n \le 100000\)

贰、思路

这道题查询的是 \(S\),但实际上是 \(a\),而操作一中修改 \(a_i\) 也会影响到 \(S_i \sim S_n\) 的值,从而影响操作二

因此考虑维护 \(a\)

由上文,修改 \(a_i\) 会影响到 \(S_i \sim S_n\),所以我们知道操作一实际上就是对 \(S\) 区间加

查询 \(\sum\limits_{j=1}^i S_j\),实际上就是查询 \(1 \sim i\) 中各个 \(S\) 的和

因此操作二实际上就是对 \(S\) 区间查询(是特殊的,从 \(1\) 开始)

由此,我们可以想到线段树、分块、树状数组等做法

线段树时间复杂度 \(O(n log_2 n)\),但常数大,代码编写难度大,可以先放弃

分块时间复杂度 \(O(n \sqrt{n})\),这道题 \(n\) 取 \(100000\) 时接近 \(10^7\) 级别,容易被卡,可以暂时搁置

树状数组的话时间复杂度 \(O(n log_2 n)\),但常数小,代码编写难度小,对于区间查询手到擒来;

因此优先考虑树状数组

对于区间修改我们看到修改的是 \(i \sim n\)中的 \(S\) 的,可以用差分;但差分有些繁琐,而且差分是对于单点查询的,那如何不差分呢?

因此考虑好数据结构,还要再思考一个问题:如何把题目中问的与 \(a\) 无关的式子推成与 \(a\) 有关的式子

OI中,推导式子是一个常态

遇到这种有累加值的题目,我们可以首先把题目中的原式转化成与输入的 \(a\) 有关联的内容:

\[\sum\limits_{j=1}^i S_j = \sum\limits_{j=1}^i \{ \sum\limits_{k=1}^j a_k \} \]

然后我们举一些特殊例子来判断:

\(a_1\) 被 \(1 \sim i\) 的每一个 \(S\) 都计算了一遍,一共计算了 \(i-1+1=i\) 次

\(a_2\) 被 \(2 \sim i\) 的每一个 \(S\) 都计算了一遍,一共计算了 \(i-2+1=i-1\) 次

…………

\(a_i\) 被 \(i \sim i\) 的每一个 \(S\) 都计算了一边,一共计算了 \(i-i+1=1\) 次

然后我们可以发现,对于一个 \(a_k\),它对 \(1 \sim i\) 的这么一个查询,如果设它的 贡献 为它为答案贡献的数值,

那它的 贡献 便是它本身的数值乘上它在前缀和里面出现的次数,即 \(Contribute(k)=a_k \cdot cnt_k=a_k \cdot (i-k+1)\)

每个 \(a_k\) 的贡献之和便是要查询的答案

所以

\[\sum\limits_{j=1}^i \{ \sum\limits_{k=1}^j a_k \} = \sum\limits_{j=1}^i Contribute(j) = \sum\limits_{j=1}^i \{ a_j \cdot (i-j+1) \} \]

拆开,得到

\[(i+1) \cdot \sum\limits_{j=1}^i a_j - \sum\limits_{j=1}^i \{a_j \cdot j\} \]

拆到这里,想必大家都明白了,这里有两个前缀和:\(a_j\) 和 \(a_j \cdot j\)

所以我们需要维护两个树状数组,一个里面是 \(a_j\) ,另一个里面是 \(a_j \cdot j\)

然后按照这个式子写出来即可

(注意树状数组大小范围)

叄、代码

#include<bits/stdc++.h>
#define endl "\n"
#define int long long//要开 long long
using namespace std;
const int N=100009;
int n,m;
int a[N];
class tree_array
{
    private:
        int s[N<<1];
        inline int lowbit(int x){return x&(-x);}
    public://模板操作
        inline void add(int point,int val)
        {
            for(int i=point;i<=(n<<1);i+=lowbit(i)) s[i]+=val;
            return;
        }
        inline int query(int point)
        {
            int res=0;
            for(int i=point;i>=1;i-=lowbit(i)) res+=s[i];
            return res;
        }
}bit1,bit2;
//bit1 维护 aj,bit2 维护 aj*j
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    //freopen("sum.in","r",stdin);
    //freopen("sum.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];//输入
    for(int i=1;i<=n;i++)
    {
        bit1.add(i,a[i]);
        bit2.add(i,a[i]*i);//建立树状数组
    }
    while(m--)
    {
        string str;
        int u,x;
        cin>>str>>u;
        if(str=="Modify")
        {
            cin>>x;
            bit1.add(u,x-a[u]);
            bit2.add(u,(x-a[u])*u);//修改一下
            a[u]=x;
        }
        else
        {
            int res=(u+1)*bit1.query(u)-bit2.query(u);//按照推的式子输出即可
            cout<<res<<endl;
        }
    }
    return 0;
} 

标签:limits,int,题解,sum,查询,cdot,Preprefix,sim
From: https://www.cnblogs.com/DreamerX/p/LG4868_Preprefix_sum_Solution.html

相关文章

  • Python中的怎么引进SUM函数
    在Python中,我们可以使用内置的sum()函数来计算序列中所有元素的总和。sum()函数接受一个可迭代对象作为参数,并返回其元素的总和。下面是一个示例代码,展示了如何使用sum()函数来计算列表中所有元素的总和:numbers=[1,2,3,4,5]total=sum(numbers)print("总和为:",total)......
  • Sum of (-1)^f(n)
    煎蛋提。不妨令\(g(i)=(-1)^{f(i)}\),由\(f(i)\)的和性不难推出\(g(i)\)为完全积性函数,因此可以考虑杜教筛。考察\(g(n)\)和恒等函数\(I(n)=1\)的卷积\(g*I\),不难发现\((g*I)(p^k)=\sum\limits_{i=0}^kg(p^i)=\sum\limits_{i=0}^k(-1)^i=[2\midi]\),又由于\(g*I\)为......
  • 题解 POJ3318【Matrix Multiplication】
    postedon2022-10-2119:56:08|under题解|sourceproblem判断三个\(n\timesn\)的矩阵是否满足\(A\timesB=C\),\(n\leq500\)。solution随机一个行向量\(v\)。若\(a\timesb=c\),则有\(v\timesa\timesb=v\timesc\)(不充分)。显然相乘复杂度仅为\(O(n^2)\)。类似于......
  • ARC145F Modulo Sum of Increasing Sequences
    为数不多不用多项式科技的单位根反演题。\(A\)不降比较难搞,所以首先令\(B_i=A_i+i-1\),则\(B\)单调递增。转化为对任意的\(k\in[0,\text{MOD}-1]\),求在\([0,N+M-1]\)中选\(N\)个不同的数,总和对\(\text{MOD}\)取模为\(k\)的方案数。记\(p=\text{MOD},n=N+M\)。列出......
  • 题解 P4955 【[USACO14JAN]Cross Country Skiing S】
    postedon2021-02-2710:04:32|under题解|source这道题其实没有绿这么难,只需要二分+搜索就行了。读入。注意尽量不要用scanf读入bool,这好像是UB,可以用一个变量\(x\)存输入的数,然后直接类型转换。二分。套模版就行了,等一下我们再写\(\operatorname{check}()\)函......
  • CF1152F2 Neko Rules the Catniverse (Large Version) 题解
    发现挨位考虑填哪个不太现实,考虑值域。令\(dp_{i,j,st}\)表示考虑到\(i\),此时序列长度为\(j\),\(i-m\)到\(i-1\)填空状态为\(st\)的方案数,考虑选/不选数即可:\(dp_{i,j,st}\times(\text{popcount}(st)+1)\todp_{i+1,j+1,(2st+1)\&2^m},dp_{i+1,j,(2st)\&2^m}\)乘上那......
  • 题解 //「BZOJ2406」矩阵
    赛时公告现在呢?:现在有弹窗了吗「2023-07-1916:45:07」此时无声胜有声。F.「BZOJ2406」矩阵http://222.180.160.110:1024/contest/3825/problem/7这是头一次见识到把矩阵和网络流结合在一起的题目。不过这种处理方式也是我们在学习二分图时的常客了:把行和列连边表示某一元......
  • 【题解】Luogu[P3360] 偷天换日
    solution开题显然是个树形dp,只不过在树形dp上又增加了背包问题。我们不妨将每个走廊看成一个点,把交叉口看成边(当然也可以把交叉口看成点,不过写起来麻烦一些),于是就转化为了一棵二叉树。我们设\(f_{i,j}\)表示以\(i\)为根的子树内,花费了不超过\(j\)时间,能拿到的最大价值......
  • sum
    sum计算文件的校验码和显示块数补充说明sum命令用于计算并显示指定文件的校验和与文件所占用的磁盘块数。语法sum(选项)(参数)选项-r:使用BSD的校验和算法,块大小为1k;-s:使用systemV的校验和算法,块大小为512字节。参数文件列表:需要计算和与磁盘块数的文件列表。实例......
  • Frog 3 题解
    Frog3题目大意题意都这么明确了还要这个干什么。存在\(n\)个点,每个点有一个属性\(h_i\),\(h_i\)单增,从点\(i\)移动到点\(j(j>i)\)的代价是\((h_i-h_j)^2+C\),其中\(C\)是给定的常数,求从点\(1\)移动到点\(n\)的最小代价。思路分析斜率优化DP板题。设\(f_i\)......