PS:如果读过题了可以跳过题目描述直接到题解部分
提交链接:洛谷 [COCI2015-2016#1] RELATIVNOST
您是一位计数大师,有一天您的朋友 Luka 出了一道问题来刁难您。
Luka 是一位勤劳的画家,他的画很好,所以会有 n n n 个人来买他的画。
画分两种,黑白画与彩色画。
Luka 十分勤劳,所以他有无穷多的画。
Luka 讨厌出售黑白画,所以他希望至少有 c c c 个人会买走一张彩色画。
第 i i i 个人会至多购买 a i a_i ai 张彩色画, b i b_i bi 张黑白画,且它们会至少购买一幅画。
但是,客户们只能单独购买彩色画或黑白画。
客户们会不断改变 a i a_i ai 与 b i b_i bi,这种改变会持续 q q q 次。
客户以 1 ∼ n 1\sim n 1∼n 编号。
您需要求出在每次改变之后,Luka 会有几种方案满足所有需求。
为了防止输出太大,Luka 只需要您告诉他方案数 m o d 1 0 4 + 7 \bmod\ 10^4+7 mod 104+7 的值。
第一行为两个整数 n , c n,c n,c。
第二行为 n n n 个整数 a i a_i ai。
第三行为 n n n 个整数 b i b_i bi。
第四行为一个整数 q q q。
接下来 q q q 行,一行三个整数 p i , a p i , b p i p_i,a_{p_i},b_{p_i} pi,api,bpi,第 i i i 行表示标号 p i p_i pi 的顾客将 a i a_i ai 和 b i b_i bi 更换成 a p i a_{p_i} api 和 b p i b_{p_i} bpi。
共 q q q 行,一行一个整数,第 i i i 行的值表示进行了第 i i i 次改变后,满足条件的方案数 m o d 1 0 4 + 7 \bmod\ 10^4+7 mod 104+7 的值。
2 2
1 1
1 1
1
1 1 1
1
2 2
1 2
2 3
2
1 2 2
2 2 2
4
4
4 2
1 2 3 4
1 2 3 4
1
4 1 1
66
第一次改变后,我们只有唯一的一种方案,就是向两位用户都出售一张彩色画。
本题满分 140 140 140 分。
本题译自 Croatian Open Competition in Informatics 2015/2016 Contest #1 T5 RELATIVNOST。
注意为了节约内存,我们需要把线段树的 l l l和 r r r省略掉,用位运算来查找。
2022.10.26
因为有人受我题解写得太水的影响,专门绕过一个人走过来问我,所以我决定补充一下题解。
对于线段树的每个节点,保存的是第
l
l
l到
r
r
r个人的信息,我们先不管它存的是什么信息,反正指到这个节点,就是说的这些人。
比如我们看到上图这个线段树,红色的数字表示节点编号,黑色的数字就表示该节点存的人的信息。
然后问题就来了,节点里面到底存的这些人的什么信息呢?
这当然就要说到dp的定义了。
我们定义 d p i , j dp_{i,j} dpi,j表示 i i i号节点中买 j j j张彩色画的情况数。
注意如果买画的张数多于 c c c张我们都把它的情况数计入 d p i , c dp_{i,c} dpi,c。
转移方程当然是用乘法原理直接两层循环用两个子节点更新父节点啦。
想必做到这道题的人代码阅读能力都不弱,具体的方程就自己详见 u p d a t e update update函数内部吧。
提醒一下,洛谷上要想过一定要开O2优化!!!!!
//洛谷 [COCI2015-2016#1] RELATIVNOST
#pragma GCC optimize(3)
#include
#include
using namespace std;
const int mo=10007;
int n,c;
int a[100010];
int b[100010];
int q;
int p,ap,bp;
short t[400010][21];
void in(int &x){
int nt;
x=0;
while(!isdigit(nt=getchar()));
x=nt^'0';
while(isdigit(nt=getchar())){
x=(x<<3)+(x<<1)+(nt^'0');
}
}
void out(register int x){
if(x>9) out(x/10ll);
putchar(x%10ll^48ll);
}
void update(int x){
for(int i=0;i<=c;++i){
t[x][i]=0;
}
for(int i=0;i<=c;++i){
for(int j=0;j<=c;++j){
t[x][min(i+j,c)]+=(1ll*t[x<<1][i]*t[x<<1|1][j])%mo;
t[x][min(i+j,c)]%=mo;
}
}
}
void build(int x,int l,int r){
if(l==r){
t[x][1]=a[l];
t[x][0]=b[l];
return;
}
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
update(x);
}
void change(int x,int l,int r,int p,int pa,int pb){
if(l==r){
t[x][1]=pa;
t[x][0]=pb;
return;
}
int mid=l+r>>1;
if(p<=mid){
change(x<<1,l,mid,p,pa,pb);
}
else{
change(x<<1|1,mid+1,r,p,pa,pb);
}
update(x);
}
int main(){
register int i,j;
in(n),in(c);
for(i=1;i<=n;++i){
in(a[i]);
a[i]%=mo;
}
for(i=1;i<=n;++i){
in(b[i]);
b[i]%=mo;
}
build(1,1,n);
in(q);
for(i=1;i<=q;++i){
in(p),in(ap),in(bp);
ap%=mo;
bp%=mo;
change(1,1,n,p,ap,bp);
out(t[1][c]);
putchar('\n');
}
return 0;
}