bzoj4597 [Shoi2016]随机序列
2016-12-18 23:14
387 查看
【题意】
n个数,任意相邻两数之间加入“+”“-”“*”三种符号中的一种,数列的答案即为这3^(n-1)种表达式的和mod(10^9+7)的值。
m次修改,每次修改一个数并求出数列的答案。
【数据范围】
n<=100000,m<=100000,1<=数列中的数<=10000
【思路】
设w=10000。
定义一个区间[L,R]中的符号均为“*”,且L前与R后的符号不为“*”。
由于“+”“-”可相互抵消,对于所有L>=2的区间,L前面的符号不为“*”(定义),“+”“-”次数相同,故这样的区间对答案贡献为0。
故答案由若干L=1的区间计算得到:
若L=1且R=n,后面没有符号位,故它对答案贡献1次。
若L=1且R<n,后面的符号任意填,故共有2*3^(n-R-1)种填法,贡献2*3^(n-R-1)次。
每次修改相当于一个后缀区间/原数*现数,/原数相当于*原数的逆元,逆元可预处理得到。故问题变为维护区间修改(乘一个数),整体求和,裸线段树。
【时间复杂度】
O((n+m) log n+w log (10^9+7))
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100010
#define ll long long
#define mod 1000000007
using namespace std;
struct tt{int a, b, l, r, s, f;}t[N*2];
int n, m, w
, bin
, v
, now, l, inv
, x, y, z;
inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int pow(int y, int x){
int s=1, t=y;
while(x){
if(x&1)s=(ll)s*t%mod;
t=(ll)t*t%mod; x>>=1;
}
return s;
}
void update(int i){
t[i].s=(t[t[i].l].s+t[t[i].r].s)%mod;
}
void maketree(int L, int R){
t[l].a=L; t[l].b=R; t[l].l=t[l].r=t[l].s=0; t[l].f=1;
if(L<R){
int mid=(L+R)>>1, l1=l;
l++; t[l1].l=l; maketree(L, mid);
l++; t[l1].r=l; maketree(mid+1, R);
update(l1);
}else t[l].s=v[L];
}
void pushdown(int i){
if(t[i].f>1){
t[t[i].l].f=(ll)t[t[i].l].f*t[i].f%mod;
t[t[i].l].s=(ll)t[t[i].l].s*t[i].f%mod;
t[t[i].r].f=(ll)t[t[i].r].f*t[i].f%mod;
t[t[i].r].s=(ll)t[t[i].r].s*t[i].f%mod;
t[i].f=1;
}
}
void ins(int i, int a, int b, int c){
if(a<=t[i].a&&t[i].b<=b){
t[i].f=(ll)t[i].f*c%mod; t[i].s=(ll)t[i].s*c%mod;
return;
}
pushdown(i);
int mid=(t[i].a+t[i].b)>>1;
if(a<=mid)ins(t[i].l, a, b, c);
if(mid<b)ins(t[i].r, a, b, c);
update(i);
}
int main(){
n=read(); m=read();
for(int i=1; i<=n; i++)w[i]=read();
bin[0]=2;
for(int i=1; i<=n; i++)bin[i]=(ll)bin[i-1]*3%mod;
for(int i=0; i<=10000; i++)inv[i]=pow(i, mod-2);
now=1;
for(int i=1; i<=n; i++){
now=(ll)now*w[i]%mod;
if(i<=n-1)v[i]=(ll)now*bin[n-i-1]%mod; else v[i]=now;
}
l=1; maketree(1, n);
for(int i=1; i<=m; i++){
x=read(); y=read();
z=(ll)inv[w[x]]*y%mod; w[x]=y;
ins(1, x, n, z); printf("%d\n", t[1].s);
}
return 0;
}
n个数,任意相邻两数之间加入“+”“-”“*”三种符号中的一种,数列的答案即为这3^(n-1)种表达式的和mod(10^9+7)的值。
m次修改,每次修改一个数并求出数列的答案。
【数据范围】
n<=100000,m<=100000,1<=数列中的数<=10000
【思路】
设w=10000。
定义一个区间[L,R]中的符号均为“*”,且L前与R后的符号不为“*”。
由于“+”“-”可相互抵消,对于所有L>=2的区间,L前面的符号不为“*”(定义),“+”“-”次数相同,故这样的区间对答案贡献为0。
故答案由若干L=1的区间计算得到:
若L=1且R=n,后面没有符号位,故它对答案贡献1次。
若L=1且R<n,后面的符号任意填,故共有2*3^(n-R-1)种填法,贡献2*3^(n-R-1)次。
每次修改相当于一个后缀区间/原数*现数,/原数相当于*原数的逆元,逆元可预处理得到。故问题变为维护区间修改(乘一个数),整体求和,裸线段树。
【时间复杂度】
O((n+m) log n+w log (10^9+7))
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100010
#define ll long long
#define mod 1000000007
using namespace std;
struct tt{int a, b, l, r, s, f;}t[N*2];
int n, m, w
, bin
, v
, now, l, inv
, x, y, z;
inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int pow(int y, int x){
int s=1, t=y;
while(x){
if(x&1)s=(ll)s*t%mod;
t=(ll)t*t%mod; x>>=1;
}
return s;
}
void update(int i){
t[i].s=(t[t[i].l].s+t[t[i].r].s)%mod;
}
void maketree(int L, int R){
t[l].a=L; t[l].b=R; t[l].l=t[l].r=t[l].s=0; t[l].f=1;
if(L<R){
int mid=(L+R)>>1, l1=l;
l++; t[l1].l=l; maketree(L, mid);
l++; t[l1].r=l; maketree(mid+1, R);
update(l1);
}else t[l].s=v[L];
}
void pushdown(int i){
if(t[i].f>1){
t[t[i].l].f=(ll)t[t[i].l].f*t[i].f%mod;
t[t[i].l].s=(ll)t[t[i].l].s*t[i].f%mod;
t[t[i].r].f=(ll)t[t[i].r].f*t[i].f%mod;
t[t[i].r].s=(ll)t[t[i].r].s*t[i].f%mod;
t[i].f=1;
}
}
void ins(int i, int a, int b, int c){
if(a<=t[i].a&&t[i].b<=b){
t[i].f=(ll)t[i].f*c%mod; t[i].s=(ll)t[i].s*c%mod;
return;
}
pushdown(i);
int mid=(t[i].a+t[i].b)>>1;
if(a<=mid)ins(t[i].l, a, b, c);
if(mid<b)ins(t[i].r, a, b, c);
update(i);
}
int main(){
n=read(); m=read();
for(int i=1; i<=n; i++)w[i]=read();
bin[0]=2;
for(int i=1; i<=n; i++)bin[i]=(ll)bin[i-1]*3%mod;
for(int i=0; i<=10000; i++)inv[i]=pow(i, mod-2);
now=1;
for(int i=1; i<=n; i++){
now=(ll)now*w[i]%mod;
if(i<=n-1)v[i]=(ll)now*bin[n-i-1]%mod; else v[i]=now;
}
l=1; maketree(1, n);
for(int i=1; i<=m; i++){
x=read(); y=read();
z=(ll)inv[w[x]]*y%mod; w[x]=y;
ins(1, x, n, z); printf("%d\n", t[1].s);
}
return 0;
}
相关文章推荐
- 【bzoj4597】 [Shoi2016]随机序列
- [BZOJ4597][SHOI2016]随机序列(线段树)
- 【BZOJ4597】[Shoi2016]随机序列 线段树
- [bzoj4597][Shoi2016]随机序列 线段树
- bzoj 4597: [Shoi2016]随机序列
- 【BZOJ4597】【Shoi2016】随机序列 线段树
- BZOJ 4597: [Shoi2016]随机序列
- 【bzoj4597】[Shoi2016]随机序列 线段树
- 【bzoj4597】【Shoi2016】【随机序列】【线段树】
- bzoj 4597: [Shoi2016]随机序列 线段树
- 4597: [Shoi2016]随机序列
- bzoj4596 [Shoi2016]黑暗前的幻想乡
- bzoj 4596: [Shoi2016]黑暗前的幻想乡【容斥原理+矩阵树定理】
- BZOJ4597 [Shoi2016]随机序列
- 【BZOJ】4596: [Shoi2016]黑暗前的幻想乡
- BZOJ4597: [Shoi2016]随机序列
- BZOJ 4596: [Shoi2016]黑暗前的幻想乡
- BZOJ4596 [Shoi2016]黑暗前的幻想乡
- BZOJ 4596: [Shoi2016]黑暗前的幻想乡 矩阵树定理 容斥原理
- [bzoj4596][SHOI2016]黑暗前的幻想乡