题目
有N个人出去旅行,第i个人去A国有Ai种游玩方式,去B国有Bi种游玩方式,问至少有C个人去A国的情况下,所有人的游玩方式有多少种不同的可能。
两种所有人的游玩方式不同当且仅当存在一个人选择的游玩方式不同,或选择去的国家不同。
接下来有P次修改,每次修改一个人的Ai和Bi。
总方案数要 mod 10007
解题思路
找突破口。
寻找是哪C个去A国,甚至去A国的人数要比C大,这种枚举方法显然不行。
但是,需要求一种方案,使得既知道去的人的范围,也知道有多少个人去A国。
题目要求支持单点修改。并且C很小。
所以利用线段树的每个点维护一个数组
f[]
f
[
]
,
f[i]
f
[
i
]
表示区间
[l,r]
[
l
,
r
]
中去A国的人有
i
i
个的答案。
通过线段树合并,则
通过 min(C,x+y) m i n ( C , x + y ) 可以表示 f[C] f [ C ] 是区间内大于等于 C C 的答案。
最后答案是。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 93010
#define mo 10007
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
int mat[22],sum[22];
};note tr[N*4];
int i,j,k,l,n,m,C,ans;
int a[N],b[N];
int read(){
int fh=1,rs=0;char ch;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return fh*rs;
}
void write(int x){if(x>9)write(x/10);P(x%10+'0');}
void add(int &x,int y){x=(x+y)%mo;}
void update(int ps){
int l=ps<<1,r=l|1,i,j,k;
fo(i,0,C)tr[ps].mat[i]=0;
fo(k,0,C-1)
fo(i,0,k)
add(tr[ps].mat[k],(tr[l].mat[i]*tr[r].mat[k-i])%mo);
fo(i,0,C-1)if(tr[l].mat[i]){
add(tr[ps].mat[C],(tr[l].mat[i]*tr[r].sum[C])%mo);
add(tr[ps].mat[C],(tr[l].mat[i]*(mo-tr[r].sum[C-i-1]))%mo);
}
if(tr[l].mat[C])add(tr[ps].mat[C],(tr[l].mat[i]*tr[r].sum[C])%mo);
tr[ps].sum[0]=tr[ps].mat[0];
fo(i,1,C)tr[ps].sum[i]=(tr[ps].sum[i-1]+tr[ps].mat[i])%mo;
}
void build(int ps,int l,int r){
if(l==r){
int i;
fo(i,0,C)tr[ps].mat[i]=0;
tr[ps].mat[1]=a[l];
tr[ps].mat[0]=b[l];
tr[ps].sum[0]=b[l];
fo(i,0,C)tr[ps].sum[i]=(tr[ps].sum[i-1]+tr[ps].mat[i])%mo;
return;
}
int wz=(l+r)>>1;
build(ps<<1,l,wz);
build((ps<<1)|1,wz+1,r);
update(ps);
}
void change(int ps,int l,int r,int x){
if(l==r){
tr[ps].mat[1]=a[l];
tr[ps].mat[0]=b[l];
tr[ps].sum[0]=b[l];
fo(i,0,C)tr[ps].sum[i]=(tr[ps].sum[i-1]+tr[ps].mat[i])%mo;
return;
}
int wz=(l+r)>>1;
if(x<=wz)change(ps<<1,l,wz,x);
else change((ps<<1)|1,wz+1,r,x);
update(ps);
}
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
n=read();C=read();
fo(i,1,n)a[i]=read(),a[i]=a[i]%mo;
fo(i,1,n)b[i]=read(),b[i]=b[i]%mo;
build(1,1,n);
m=read();
while(m--){
k=read();a[k]=read();b[k]=read();
a[k]=a[k]%mo;b[k]=b[k]%mo;
change(1,1,n,k);
ans=tr[1].mat[C];
write(ans),P('\n');
}
return 0;
}