1349: RELATIVNOST
时间限制: 1 Sec 内存限制: 128 MB提交: 16 解决: 0
[ 提交][ 状态][ 讨论版][命题人:]
题目描述
Young Luka是个艺术商人,他有N个客户,要卖画给每个客户。
每个客户能买彩色画或者黑白画,必须买其中一种,不能都买。
第i个客户想要至多买ai幅彩色画,或者bi幅黑白画。
Luka不喜欢黑白画,如果少于c个人买彩色画,他会很难过。
他的客户们经常改变需求,也就是说,ai和bi是会变的。因此,Luka经常被这个问题困扰:“至少c人买彩色画,一共有多少种购买?”请帮助Luka解决他的问题。
输入
第一行两个整数N和C(N<=100000,C<=20)
第二行N个整数ai(ai<=1000000000)
第三行N个整数bi(bi<=1000000000)
第四行一个整数,修改的次数Q(Q<=100000)
接下来Q行,每行三个整数p,ap,bp,(1<=p<=n),表示第p个人至多买的彩色画,黑白画。
30%的数据:N,Q<=1000
输出
有Q行,每行一个整数,答案模10007。
样例输入
4 21 2 3 41 2 3 414 1 1
样例输出
66
提示
来源
题解:我看到这道题目是蒙蔽的,然后发现也并不是很难。
PS:wzp说这题普及难度
常规思路f[i][j]表示前i个人j个(j为C时表示或以上)选了彩色画的方案。用一个类似堆?(线段树?)的东西(有一个异常高端的名字叫做锦标赛树)的东西来维护,对于每一个节点i,答案为它的左儿子乘以右儿子。修改只需要修改logn个点即可。
赛后题解:Let us first solve the task for the case when there are no changes in requirements
and we solve it under constant number of requested colored paintings a i and black
and white paintings b i . We need to determine how many ways there are to choose
different configurations of selling the paintings with the requirement that at least C
paintings are colored. The initial problem when there are no changes in
requirements is solved using dynamic programming. Let dp ij denote the number of
ways to choose the initial i transactions so that exactly j requirements are satisfied
with colored paintings. The relation used to calculate dp ij is:
dp ij = dp i-1 j * b i + dp i-1 j-1 * a i
In the end, the solution is the sum of all dp n i for each i greater than or equal to C .
The calculation can be simplified even more if we define dp i K as the number of
ways for not exactly K colored paintings, but at least K colored paintings. The
solution that calculated this relation every time the requirements change has the
complexity O(N * C) and was good enough for 30% of total points.
In order to get all the points, you needed to find a way to efficiently maintain the
relation value after changes have been made. The inspiration comes from
tournament tree. If you are not familiar with this structure, be sure to read the
tutorial at http://wiki.xfer.hr/tournament/ . Under the assumption that now you
know how tournament tree works, we continue solving the task.
The solution will be maintained in a way that every node of the tournament tree is
used to store the number of ways to choose the paintings in that subtree for each
number of chosen colored paintings from 0 to K .
We are left with maintaining that relation after we change the requirements of one
person. It is evident that it is fairly simple to calculate the change in result for each
node in the tournament tree. The question is how to join two nodes.
Here we can notice that the number of ways of choosing the transaction over the
entire subtree (consisting of the left - L and right child - R ) with at least i purchases
of colored paintings is T s = Σ L i *R s - i for each i <= s .
The total time complexity is O((N + Q) lg N * K^2) .
Necessary skills : data structures, dynamic programming
Category : dynamic programming
代码(过不去,会超时的):
#include<bits/stdc++.h>
using namespace std;
int n,m,a[500001],b[500001],p=10007;
long long f[500001][22];
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void build(int x){
int i,j;
for(i=0;i<=m;i++)f[x][i]=0;
for(i=0;i<=m;i++)
for(j=0;j<=m;j++)
f[x][min(i+j,m)]+=f[x*2][i]*f[x*2+1][j];
for(i=0;i<=m;i++)f[x][i]%=p;
}
int main(){
int i,j,x,t,k,t1;
n=read();m=read();
for(i=1;i<=n;i++)a[i]=read();
for(i=1;i<=n;i++)b[i]=read();
for(i=1;i<=n;i++){
f[n+i-1][1]=a[i];
f[n+i-1][0]=b[i];
}
for(i=n-1;i;i--)build(i);
//printf("%d\n",f[1][m]);
t1=read();
for(i=1;i<=t1;i++){
x=read();t=read();k=read();
x+=n;
f[x-1][1]=t;f[x-1][0]=k;
for(j=(x-1)/2;j;j/=2)build(j);
printf("%lld\n",f[1][m]);
}
}
2018.05.24.20.30:站长帮我时限开到了2s后这个程序还是有一个点卡不过去,倒是官方题解以1917ms卡过去了。
官方题解:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef unsigned int uint;
const int MAXN = 100005;
const int MAXC = 21;
const int mod = 10007;
int n, c, q;
int a[MAXN];
int b[MAXN];
long long T[2 * MAXN][MAXC];
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)] += (T[x * 2][i] * T[x * 2 + 1][j]);
for(int i=0;i<=c;++i)
if(T[x][i]>=mod)T[x][i]%=mod;
}
void change(int x) {
x += n;
memset(T[x], 0, sizeof T[x]);
T[x][1] = a[x - n] % mod;
T[x][0] = b[x - n] % mod;
for (x /= 2; x > 0; x /= 2) update(x);
}
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(void) {
scanf("%d%d", &n, &c);
for (int i = 0; i < n; ++i) a[i]=read();
for (int i = 0; i < n; ++i) b[i]=read();
for (int i = 0; i < n; ++i) {
T[i + n][0] = b[i] ;
T[i + n][1] = a[i] ;
}
for (int i = n-1; i >= 1; --i)
update(i);
scanf("%d", &q);
for (int i = 0; i < q; ++i) {
int p;
p=read(); --p;
a[p]=read();b[p]=read();
change(p);
printf("%lld\n", T[1][c]);
}
return 0;
}