PrayerOJ1349: RELATIVNOST&COCI2016/2016 contest 1

4 篇文章 0 订阅
1 篇文章 0 订阅

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

提示

来源

coci15-16contest1 


题解:我看到这道题目是蒙蔽的,然后发现也并不是很难。

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

### 回答1: 题目描述: Eko 有一排树,每棵树的高度不同。他想要砍掉一些树,使得剩下的树的高度都相同。他希望砍掉的树的高度尽可能地少,你能帮他算出最少要砍掉多少棵树吗? 输入格式: 第一行包含两个整数 N 和 M,分别表示树的数量和 Eko 希望的树的高度。 第二行包含 N 个整数,表示每棵树的高度。 输出格式: 输出一个整数,表示最少要砍掉的树的数量。 输入样例: 9 5 2 3 4 7 8 9 10 11 12 输出样例: 3 解题思路: 二分答案 首先,我们可以发现,如果我们知道了 Eko 希望的树的高度,那么我们就可以计算出砍掉多少棵树。 具体来说,我们可以遍历每棵树,如果它的高度大于 Eko 希望的树的高度,那么就将它砍掉,否则就保留它。 然后,我们可以使用二分答案的方法来确定 Eko 希望的树的高度。 具体来说,我们可以将树的高度排序,然后二分一个可能的 Eko 希望的树的高度,然后计算砍掉多少棵树,如果砍掉的树的数量小于等于 M,那么说明 Eko 希望的树的高度可能更小,否则说明 Eko 希望的树的高度可能更大。 最后,我们可以得到最少要砍掉的树的数量。 时间复杂度:O(NlogN)。 参考代码: ### 回答2: 这道题目是一道模拟题,需要模拟机器人的移动过程以及得出最终机器人的位置和朝向。首先需要明确机器人的起始位置以及朝向,其次需要读取输入的指令,根据指令逐步移动机器人,并顺便判断是否会越界或者碰到障碍物。最后输出最终机器人的位置和朝向。 在本题中,需要按照从西向东、从北向南、从东向西、从南向北的顺序判断机器人的朝向。为了方便表述,我把机器人的朝向表示为0、1、2、3,分别代表从西向东、从北向南、从东向西、从南向北。 具体地说,机器人按照指令逐步移动时需要分情况讨论,比如: 1.当前机器人朝向为0,即从西向东: 若指令为F,则x坐标+1,但需要判断是否越界或者碰到障碍物。 若指令为L,则朝向变为3。 若指令为R,则朝向变为1。 2.当前机器人朝向为1,即从北向南: 若指令为F,则y坐标-1,但需要判断是否越界或者碰到障碍物。 若指令为L,则朝向变为0。 若指令为R,则朝向变为2。 3.当前机器人朝向为2,即从东向西: 若指令为F,则x坐标-1,但需要判断是否越界或者碰到障碍物。 若指令为L,则朝向变为1。 若指令为R,则朝向变为3。 4.当前机器人朝向为3,即从南向北: 若指令为F,则y坐标+1,但需要判断是否越界或者碰到障碍物。 若指令为L,则朝向变为2。 若指令为R,则朝向变为0。 最后输出最终机器人的位置和朝向即可。 在编写程序时需要注意判断边界和障碍物,以及要用scanf读取输入,不要用C++的cin,否则会TLE。此外,由于本题没有给出边界和障碍物,需要自己设置。最后,本题的思路不难,但是需要认真仔细地处理各种情况,多测试几组数据找出程序的漏洞,这样才能通过本题。 ### 回答3: 本题为一道组合数学题,需要运用排列组合知识进行分析。 题目要求将n个方块填入3*3的网格中,每个方块可以是红色、绿色或蓝色的一个。要求每行、每列和对角线上的方块颜色都不相同。求方案总数。 首先考虑对第一行进行颜色选取。由于第一行每个位置的颜色都不影响其他行和列,故第一行的颜色选取不影响总方案数。所以假设第一行颜色已经确定,考虑第二行的颜色选取。第二行中各位置的颜色受到第一行的限制,只有第一行某位置颜色的补集才能选取。例如,若第一行第一个位置是红色,那么第二行第一个位置不能选取红色。因为每行颜色不能相同,所以第二行受到第一行限制的位置只有3个。第三行同理,由于前两行的限制,只有2个位置可选。做完颜色选取后,再将每行的方块进行排列,此时我们可以使用错排公式得到方案数: D(n) = n!(1 - 1/1! + 1/2! - 1/3! + ... + (-1)^(n)/n!) 最终,方案总数即为每个第一行颜色选取方法下的错排方案数之和。按题意枚举第一行的颜色,就可以得到最终的方案总数了。 总结一下,本题所需要的知识点为:错排公式、颜色限制对组合数的影响、暴力枚举法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值