P6533 [COCI2015-2016#1] RELATIVNOST
题目大意
小 L L L在卖画。这些画分为彩色画和黑白画,小 L L L希望有至少 c c c个人会买走他至少一张彩色画。
第 i i i个人至多会购买 a i a_i ai张彩色画或者 b i b_i bi张黑白画,且每个人至少购买一张画。
每个人只能选择购买彩色画或黑白画。
有 q q q次修改,每次修改会选择一个 i i i并修改 a i a_i ai和 b i b_i bi。求每次修改之后能满足小 L L L的要求的买画的方案数。输出答案模 1 0 4 + 7 10^4+7 104+7后的值。
1 ≤ n , q ≤ 1 0 5 , 1 ≤ c ≤ 20 1\leq n,q\leq 10^5,1\leq c\leq 20 1≤n,q≤105,1≤c≤20
时间限制 4000 m s 4000ms 4000ms,空间限制 32 M B 32MB 32MB。
题解
设 f i , j f_{i,j} fi,j表示前 i i i个人有 j j j个人选择彩色画的方案数,则转移式为
f i , j = f i − 1 , j − 1 × a i + f i − 1 , j × b i f_{i,j}=f_{i-1,j-1}\times a_i+f_{i-1,j}\times b_i fi,j=fi−1,j−1×ai+fi−1,j×bi
因为有修改,所以我们考虑用线段树来优化。用线段树维护每一个区间的方案数,那么
t r [ k ] . f [ i + j ] + = t r [ l c ] . f [ i ] × t r [ r c ] . f [ j ] tr[k].f[i+j]+=tr[lc].f[i]\times tr[rc].f[j] tr[k].f[i+j]+=tr[lc].f[i]×tr[rc].f[j]
在只有一个人时, t r [ k ] . f [ 1 ] = a i , t r [ k ] . f [ 0 ] = b i tr[k].f[1]=a_i,tr[k].f[0]=b_i tr[k].f[1]=ai,tr[k].f[0]=bi。
空间限制为 32 M B 32MB 32MB,对于 int \text{int} int类型能开 24 × 1024 × 1024 / 4 = 8388608 24\times 1024\times 1024/4=8388608 24×1024×1024/4=8388608的大小。线段树的大小为 4 n c = 8000000 4nc=8000000 4nc=8000000, a , b a,b a,b数组的大小都是 1 0 5 10^5 105,是可行的。注意空间复杂度,能节省的空间尽量节省。
时间复杂度为 O ( n c 2 log n ) O(nc^2\log n) O(nc2logn),空间复杂度为 O ( n c ) O(nc) O(nc)。
code
#include<bits/stdc++.h>
#define lc k<<1
#define rc k<<1|1
using namespace std;
const int N=100000;
const int mod=1e4+7;
int n,c,q,a[N+5],b[N+5],tr[4*N+5][21];
void pt(int k){for(int i=0;i<=c;i++) tr[k][i]=0;for(int i=0;i<=c;i++){for(int j=0;j<=c;j++){tr[k][min(i+j,c)]=(tr[k][min(i+j,c)]+tr[lc][i]*tr[rc][j])%mod;}}
}
void build(int k,int l,int r){if(l==r){tr[k][1]=a[l]%mod;tr[k][0]=b[l]%mod;return;}int mid=l+r>>1;build(lc,l,mid);build(rc,mid+1,r);pt(k);
}
void ch(int k,int l,int r,int p,int x,int y){if(l==r&&l==p){tr[k][1]=x%mod;tr[k][0]=y%mod;return;}int mid=l+r>>1;if(p<=mid) ch(lc,l,mid,p,x,y);else ch(rc,mid+1,r,p,x,y);pt(k);
}
int main()
{scanf("%d%d",&n,&c);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=n;i++) scanf("%d",&b[i]);build(1,1,n);scanf("%d",&q);while(q--){int p,x,y;scanf("%d%d%d",&p,&x,&y);ch(1,1,n,p,x,y);printf("%d\n",tr[1][c]);}return 0;
}