Description
有N个人出去旅行,第i个人去A国有Ai种游玩方式,去B国有Bi种游玩方式,问至少有C个人去A国的情况下,所有人的游玩方式有多少种不同的可能。
两种所有人的游玩方式不同当且仅当存在一个人选择的游玩方式不同,或选择去的国家不同。
接下来有P次修改,每次修改一个人的Ai和Bi。
Input
第一行两个正整数,表示N,C,含义如题所示。
接下来一行N个整数,第i个整数表示Ai。
接下来一行N个整数,第i个整数表示Bi。
接下来一行一个正整数表示P。
接下来P行,每行三个整数i,x,y,表示修改Ai为x,Bi为y。
Output
对每次修改输出一行一个整数,表示总方案数 mod 10007。
Sample Input
4 2
1 2 3 4
1 2 3 4
1
4 1 1
Sample Output
66
Data Constraint
对于100%的数据满足:Ai,Bi,x,y在int范围内。
时间限制:1.5s
空间限制:128MB
Solution
正难则反!!!我一定要记住!
(c) 的范围很小,正着不好求就反着求,用总共的方案数减去不合法的方案数
总共的方案数就是所有的游玩方式,(total=prod_{i=1}^n(A_i+B_i))
然后就是要减去只有 (0) 个到 (c-1) 个人去A国的方案数
设计DP,(f[l][r][i])代表在第 (l) 到 (r) 这一段人中,有 (i) 个人去A国的游玩方式
暴力的转移:(f[l][r][i]=sum_{j=1}^if[l][Mid][j]*f[Mid+1][r][i-j](Mid=(l+r)/2))
这个方程设计的真的是巧妙
然后发现就可以用线段树了,这个 (l) 和 (r)正好对应上线段树的区间,pushup的时候暴力 (O(c^2)) 转移就行了
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,MAXC=25,Mod=1e4+7;
int n,c,q,A[MAXN],B[MAXN];
ll total=1;
#define Mid ((l+r)>>1)
#define lson rt<<1,l,Mid
#define rson rt<<1|1,Mid+1,r
struct SEG{
int f[MAXN<<2][MAXC];
inline void PushUp(int rt)
{
for(register int i=0;i<c;++i)f[rt][i]=0;
for(register int i=0;i<c;++i)
for(register int j=0;i+j<c;++j)(f[rt][i+j]+=f[rt<<1][i]*f[rt<<1|1][j])%=Mod;
}
inline void Build(int rt,int l,int r)
{
if(l==r)f[rt][0]=B[l],f[rt][1]=A[l];
else
{
Build(lson);
Build(rson);
PushUp(rt);
}
}
inline void Update(int rt,int l,int r,int pos)
{
if(l==r&&r==pos)f[rt][0]=B[l],f[rt][1]=A[l];
else
{
if(pos<=Mid)Update(lson,pos);
else Update(rson,pos);
PushUp(rt);
}
}
};
SEG T;
#undef Mid
#undef lson
#undef rson
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char c=' ')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(c!=' ')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline ll qexp(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)res=res*a%Mod;
a=a*a%Mod;
b>>=1;
}
return res;
}
int main()
{
read(n);read(c);
for(register int i=1;i<=n;++i)read(A[i]),A[i]%=Mod;
for(register int i=1;i<=n;++i)read(B[i]),B[i]%=Mod;
for(register int i=1;i<=n;++i)(total*=A[i]+B[i])%=Mod;
T.Build(1,1,n);
read(q);
while(q--)
{
int p,x,y;
ll res=0;
read(p);read(x);read(y);
total=total*qexp(A[p]+B[p],Mod-2)%Mod;
A[p]=x%Mod;B[p]=y%Mod;
total=total*(A[p]+B[p])%Mod;
T.Update(1,1,n,p);
for(register int i=0;i<c;++i)(res+=T.f[1][i])%=Mod;
write((total-res+Mod)%Mod,'
');
}
return 0;
}