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;
}