[Codeforces 266E]More Queries to Array...(线段树+二项式定理)
[Codeforces 266E]More Queries to Array...(线段树+二项式定理)
题面
维护一个长度为\(n\)的序列\(a\),\(m\)个操作
- 区间赋值为\(x\)
- 查询\(\sum_{i=l}^r a_i(i-l+1)^k \mod 10^9+7\)
\(n,m \leq 10^5,k \leq 5\)
分析
根据二项式定理
\]
那么
\(\begin{aligned}ans(l,r) &=\sum_{i=l}^r a_i(i-l+1)^k \\ &= \sum_{i=l}^r a_i\sum_{j=0}^k (-1)^{k-j} C_{k}^j i^j(l-1)^{k-j} \\ &= \sum_{i=l}^r \sum_{j=0}^k (a_ii^j) (-1)^{k-j} C_{k}^j (l-1)^{k-j} \\ &=\sum_{j=0}^k query(l,r,j) (-1)^{k-j} C_{k}^j (l-1)^{k-j}\end{aligned}\)
其中\(query(l,r,p)=\sum_{l=1}^r a_i^{p}\)
开\(k\)棵线段树,每棵维护\(\sum_{l=1}^r a_i^{p}\).提前预处理\(sum[i][j]\)表示\(\sum_{p=1}^{j} p^i\),修改为\(x\)的时候直接区间赋值为\(x(sum[i][r]-sum[i][l-1])\)
时间复杂度\(O(nk \log n)\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100000
#define mod 1000000007
#define maxk 5
using namespace std;
typedef long long ll;
int n,m;
inline ll fast_pow(ll x,ll k){
ll ans=1;
while(k){
if(k&1) ans=ans*x%mod;
x=x*x%mod;
k>>=1;
}
return ans;
}
inline ll inv(ll x){
return fast_pow(x,mod-2);
}
ll fact[maxn+5];
ll invfact[maxn+5];
void ini_fact(int n){
fact[0]=1;
for(int i=1;i<=n;i++) fact[i]=fact[i-1]*i%mod;
invfact[n]=inv(fact[n]);
for(int i=n-1;i>=0;i--) invfact[i]=invfact[i+1]*(i+1)%mod;
}
inline ll C(int n,int m){
return fact[n]*invfact[n-m]%mod*invfact[m]%mod;
}
ll sump[maxk+5][maxn+5];
void ini_pow(int n,int k){
for(int i=0;i<=k;i++){
for(int j=1;j<=n;j++){
sump[i][j]=(sump[i][j-1]+fast_pow(j,i))%mod;
}
}
}
inline ll get_sump(int k,int l,int r){
return (sump[k][r]-sump[k][l-1]+mod)%mod;
}
struct segment_tree{
struct node{
int l;
int r;
ll val;
ll mark;
}tree[maxn*4+5];
int kk;//记录当前维护的是a[i]^k
void push_up(int pos){
tree[pos].val=(tree[pos<<1].val+tree[pos<<1|1].val)%mod;
}
void build(int l,int r,int *a,int pos){
tree[pos].l=l;
tree[pos].r=r;
tree[pos].mark=-1;
if(l==r){
tree[pos].val=a[l]*fast_pow(l,kk);
return;
}
int mid=(l+r)>>1;
build(l,mid,a,pos<<1);
build(mid+1,r,a,pos<<1|1);
push_up(pos);
}
inline void add_mark(int pos,int mark){
tree[pos].mark=mark;
tree[pos].val=mark*get_sump(kk,tree[pos].l,tree[pos].r)%mod;
}
void push_down(int pos){
if(tree[pos].mark!=-1){
add_mark(pos<<1,tree[pos].mark);
add_mark(pos<<1|1,tree[pos].mark);
tree[pos].mark=-1;
}
}
void update(int L,int R,int val,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
add_mark(pos,val);
return;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update(L,R,val,pos<<1);
if(R>mid) update(L,R,val,pos<<1|1);
push_up(pos);
}
ll query(int L,int R,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
return tree[pos].val;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
ll ans=0;
if(L<=mid) ans=(ans+query(L,R,pos<<1))%mod;
if(R>mid) ans=(ans+query(L,R,pos<<1|1))%mod;
return ans;
}
}T[6];
int a[maxn+5];
int main(){
char cmd[2];
int l,r,x,k;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ini_fact(maxk);
ini_pow(n,maxk);
for(int i=0;i<=maxk;i++){
T[i].kk=i;
T[i].build(1,n,a,1);
}
for(int t=1;t<=m;t++){
scanf("%s",cmd);
if(cmd[0]=='='){
scanf("%d %d %d",&l,&r,&x);
for(int i=0;i<=maxk;i++) T[i].update(l,r,x,1);
}else{
scanf("%d %d %d",&l,&r,&k);
ll ans=0;
//按照二项式定理,把a[i](i-l+1)^k展开
//(-1)^j*C(k,j)*a[i]*i^j*(l-1)^(k-j)
for(int j=0;j<=k;j++){
// printf("db: %lld\n",fast_pow(-1,j));
// printf("db: %lld\n",C(k,j));
// printf("db: %lld\n",T[j].query(l,r,1));
// printf("db: %lld\n",fast_pow(l-1,k-j));
ans+=fast_pow(-1,k-j)*C(k,j)%mod*T[j].query(l,r,1)%mod*fast_pow(l-1,k-j)%mod;
ans=(ans+mod)%mod;
ans%=mod;
}
printf("%lld\n",ans);
}
}
}
[Codeforces 266E]More Queries to Array...(线段树+二项式定理)的更多相关文章
- 暑假集训单切赛第一场 CF 266E More Queries to Array(线段树+二项式展开式)
比赛时,第二题就是做的这个,当时果断没仔细考虑,直接用线段树暴力求.结果易想而知,超时了. 比赛后搜了搜题解,恍然大悟. 思路:显然用线段树,但是由于每次查询都会有变,所以不可能存储题目中的式子. ...
- CodeForces 266E More Queries to Array...(线段树+式子展开)
开始觉得是规律题的,自以为是的推了一个规律,结果测试数据都没过....看了love神的博客才发现只是把式子展开就找到规律了.不过挺6的是我虽然想错了,但是维护的的东西没有错,只是改改(改了进两个小时好 ...
- Codeforces 1114F Please, another Queries on Array? 线段树
Please, another Queries on Array? 利用欧拉函数的计算方法, 用线段树搞一搞就好啦. #include<bits/stdc++.h> #define LL ...
- codeforces 719E E. Sasha and Array(线段树)
题目链接: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input sta ...
- [Codeforces266E]More Queries to Array...——线段树
题目链接: Codeforces266E 题目大意:给出一个序列$a$,要求完成$Q$次操作,操作分为两种:1.$l,r,x$,将$[l,r]$的数都变为$x$.2.$l,r,k$,求$\sum\li ...
- Codeforces 1114F Please, another Queries on Array? [线段树,欧拉函数]
Codeforces 洛谷:咕咕咕 CF少有的大数据结构题. 思路 考虑一些欧拉函数的性质: \[ \varphi(p)=p-1\\ \varphi(p^k)=p^{k-1}\times (p-1)= ...
- Codeforces 719 E. Sasha and Array (线段树+矩阵运算)
题目链接:http://codeforces.com/contest/719/problem/E 题意:操作1将[l, r] + x; 操作2求f[l] + ... + f[r]; 题解:注意矩阵可以 ...
- Can you answer these queries? HDU 4027 线段树
Can you answer these queries? HDU 4027 线段树 题意 是说有从1到编号的船,每个船都有自己战斗值,然后我方有一个秘密武器,可以使得从一段编号内的船的战斗值变为原来 ...
- [Codeforces 280D]k-Maximum Subsequence Sum(线段树)
[Codeforces 280D]k-Maximum Subsequence Sum(线段树) 题面 给出一个序列,序列里面的数有正有负,有两种操作 1.单点修改 2.区间查询,在区间中选出至多k个不 ...
随机推荐
- Python3学习笔记(十七):requests模块
官方中文文档:http://docs.python-requests.org/zh_CN/latest/
- dstat命令 来自: http://man.linuxde.net/dstat
来自: http://man.linuxde.net/dstat
- C++入门经典-例6.22-字符串与数组,string类型的数组
1:数组中存储的数据也可以是string类型的.代码如下: // 6.22.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include ...
- 20175215 2018-2019-2 第十一周java课程学习总结
第13章 Java网络编程 13.1 URL类 URL类是java.net包中的一个重要的类,URL的实例封装着一个统一资源定位符(Uniform Resource Locator),使用URL创建对 ...
- kernel hacking的一些网站
很全面的网站,下面的网站基本都可以从该地址找到. 新手必备 subscrible/unsubscrible mail list mail list archive kernel git mainlin ...
- [go]os.Open方法源码
file, err := os.Open("./buf.go") func Open(name string) (*File, error) { return OpenFile(n ...
- LC 963. Minimum Area Rectangle II
Given a set of points in the xy-plane, determine the minimum area of any rectangle formed from these ...
- rest 参数与扩展运算符
rest 参数与扩展运算符 1.rest 参数 ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了.rest 参数搭配的变量是一个数组 ...
- JSTL核心标签库详解
<c:out>标签 标签用于输出一段文本到浏览器中. 属性名 是否支持EL 属性类型 属 性 描 述 value true Object 指定要输出的内容 escapeXml true B ...
- -moz-box-shadow
css的box-shadow是用来添加边框阴影效果的. 属性值详解: 1.inset可选值,默认阴影在盒子外使用inset后,阴影在盒子内,即使指定边框或者透明边框,阴影依然存在. 2.<off ...