題目大意:給定n個數,要求支援區間加,區間取相反數,區間查詢任意選c(c<=20)個數的所有方案中乘積的和
和維護k次方的和很像,想要維護選c個數,就要把選1~c個數的方案全部維護出來
這樣當合併兩個區間的時候(pushup),只需要列舉左右區間分別取了幾個數即可
現在考慮兩種修改操作:
1.區間取相反數
發現這種操作只會影響區間選奇數個數的情況,把這些答案全部變成相反數即可
2.區間加
這個就比較厲害了,首先我們考慮c=2的情況
設總個數為len,這些數分別為a1
,a2.
..al
en,則 ∑i
=1le
n∑j=
1i−1
(ai+
v)(a
j+v)
=∑i=
1len
∑j=1
i−1(
aiaj
+v2+
(ai+
aj)v
)=∑i
=1le
n∑j=
1i−1
aiaj
+c2l
env2
+c1l
en−1
∑i=1
lena
iv同理可求得c=3時的式子,所以只需要預處理出組合數,就可以遞推了
總時間複雜度o(
mlog
n∗202
)
#include#include#include#include#define n 100010
using namespace std;
struct ppp;
int a[n];
int c[n][21];
int mod=19940417;
int l[n<<2],r[n<<2],t[n<<2];
bool rev[n<<2];
ppp w[n<<2];
ppp ret;
ppp operator +(const ppp &x,const ppp &y)
void pup(int x)
void pudrev(int x)
int ksm(int d,int c)
return ret;
}void pudadd(int x,int v)
void pud(int x)
if(t[x])
}void build(int
now,int ll,int rr)
intmid=(ll+rr)>>1;
build(now
<<1,ll,mid);
build(now
<<1|1,mid+1,rr);
pup(now);
}void change(int
now,int ll,int rr,int v)
pud(now);
intmid=(l[now]+r[now])>>1;
if(rr<=mid) change(now
<<1,ll,rr,v);
else
if(ll>mid) change(now
<<1|1,ll,rr,v);
else change(now
<<1,ll,mid,v),change(now
<<1|1,mid+1,rr,v);
pup(now);
}void reverse(int
now,int ll,int rr)
pud(now);
intmid=(l[now]+r[now])>>1;
if(rr<=mid) reverse(now
<<1,ll,rr);
else
if(ll>mid) reverse(now
<<1|1,ll,rr);
else reverse(now
<<1,ll,mid),reverse(now
<<1|1,mid+1,rr);
pup(now);
}ppp check(int
now,int ll,int rr)
int main()
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
char s[10];
while(q--)
else
if(s[0]=='r') reverse(1,x,y);
else
}}
bzoj2962 序列操作
有乙個長度為n的序列,有三個操作1.i a b c表示將 a,b 這一段區間的元素集體增加c,2.r a b表示將 a,b 區間內所有元素變成相反數,3.q a b c表示詢問 a,b 這一段區間中選擇c個數相乘的所有方案的和mod 19940417的值。第一行兩個數n,q表示序列長度和操作個數。第...
bzoj 2962 序列操作
time limit 50 sec memory limit 256 mb submit status discuss 有乙個長度為n的序列,有三個操作1.i a b c表示將 a,b 這一段區間的元素集體增加c,2.r a b表示將 a,b 區間內所有元素變成相反數,3.q a b c表示詢問 a...
BZOJ 2962 序列操作
有乙個長度為n的序列,有三個操作1.i a b c表示將 a,b 這一段區間的元素集體增加c,2.r a b表示將 a,b 區間內所有元素變成相反數,3.q a b c表示詢問 a,b 這一段區間中選擇c個數相乘的所有方案的和mod 19940417的值。第一行兩個數n,q表示序列長度和操作個數。第...