60+100+0=160

贪婪大陆

面对蚂蚁们的疯狂进攻,小FF的Tower defence宣告失败……人类被蚂蚁们逼到了Greed Island上的一个海湾。现在,小FF的后方是一望无际的大海, 前方是变异了的超级蚂蚁。 小FF还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造SCV布置地雷以阻挡蚂蚁们的进攻。

小FF最后一道防线是一条长度为N的战壕, 小FF拥有无数多种地雷,而SCV每次可以在[ L , R ]区间埋放同一种不同于之前已经埋放的地雷。 由于情况已经十万火急,小FF在某些时候可能会询问你在[ L' , R'] 区间内有多少种不同的地雷, 他希望你能尽快的给予答复。

输入格式:

第一行为两个整数n和m; n表示防线长度, m表示SCV布雷次数及小FF询问的次数总和。

接下来有m行, 每行三个整数Q,L , R; 若Q=1 则表示SCV在[ L , R ]这段区间布上一种地雷, 若Q=2则表示小FF询问当前[ L , R ]区间总共有多少种地雷。

输出格式:

对于小FF的每次询问,输出一个答案(单独一行),表示当前区间地雷总数。

样例输入:

5 4

1 1 3

2 2 5

1 2 4

2 3 5

样例输出:

1

2

数据范围:

对于30%的数据: 0<=n, m<=1000;

对于100%的数据: 0<=n, m<=10^5.

时间限制:

1S

空间限制:

50M

题解

看题发现答案=区间内端点的个数-区间内包含的线段个数+包含了区间的线段个数。

先想分块,左端点分块右端点排序,搞出来一个\(O(n \sqrt{n} \log n)\)的做法,放弃。

然后发现线段树套平衡树直接就可以做,码出来发现set的迭代器不支持减法。

于是我去学__gnu_pbds::tree,搞了好久终于对了。时间复杂度\(O(n \log^2 n)\),60分。上厕所听别人说那个分块算法有80……

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define pbds __gnu_pbds
#define co const
#define il inline
template<class T> T read(){
T x=0,w=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T>il T read(T&x){
return x=read<T>();
}
typedef pbds::tree<std::pair<int,int>,pbds::null_type,std::less<std::pair<int,int> >,pbds::rb_tree_tag,pbds::tree_order_statistics_node_update> tree; co int N=100000+1,INF=1e9;
#define lc (x<<1)
#define rc (x<<1|1)
int n,m;
tree ls,rs,s[N<<2];
void insert(int x,int l,int r,int p,int v,int id){
s[x].insert(std::make_pair(v,id));
if(l==r) return;
int mid=(l+r)>>1;
if(p<=mid) insert(lc,l,mid,p,v,id);
else insert(rc,mid+1,r,p,v,id);
}
int qin(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return s[x].order_of_key(std::make_pair(qr,INF))-s[x].order_of_key(std::make_pair(ql,-INF));
int mid=(l+r)>>1;
if(qr<=mid) return qin(lc,l,mid,ql,qr);
if(ql>mid) return qin(rc,mid+1,r,ql,qr);
return qin(lc,l,mid,ql,qr)+qin(rc,mid+1,r,ql,qr);
}
int qout(int x,int l,int r,int ql,int qr){
if(r<ql) return s[x].order_of_key(std::make_pair(INF,INF))-s[x].order_of_key(std::make_pair(qr,INF));
int mid=(l+r)>>1;
if(ql<=mid+1) return qout(lc,l,mid,ql,qr);
return qout(lc,l,mid,ql,qr)+qout(rc,mid+1,r,ql,qr);
}
int main(){
// freopen("testdata.in","r",stdin),freopen("testdata.ans","w",stdout);
read(n),read(m);
for(int i=1;i<=m;++i){
int q=read<int>(),l=read<int>(),r=read<int>();
if(q==1){
ls.insert(std::make_pair(l,i)),rs.insert(std::make_pair(r,i));
insert(1,1,n,l,r,i);
}
else{
int ans=0;
ans+=ls.order_of_key(std::make_pair(r,INF))-ls.order_of_key(std::make_pair(l,-INF));
ans+=rs.order_of_key(std::make_pair(r,INF))-rs.order_of_key(std::make_pair(l,-INF));
ans-=qin(1,1,n,l,r);
ans+=qout(1,1,n,l,r);
printf("%d\n",ans);
}
}
return 0;
}

正解是树状数组,我们只需要每次埋地雷的时候,我们只需要标记一下当前区间的开头和结尾,我们查的时候,我们只需要查1到当前区间结尾中包含了多少个开头(一个开头代表了一种地雷)然后我们查1到当前区间前一个位置包含了多少个结尾(一个结尾代表我们一种地雷埋完了,就是我们看前面有几种地雷被埋完了!)然后把这个做差,我们就可以知道有多少种地雷是出现在当前区间中。时间复杂度\(O(n \log n)\)

多人背包

DD 和好朋友们要去爬山啦!他们一共有 K 个人,每个人都会背一个包。这些包的容量是相同的,都是 V。可以装进背包里的一共有 N 种物品,每种物品都有给定的体积和价值。

在 DD 看来,合理的背包安排方案是这样的:

  1. 每个人背包里装的物品的总体积恰等于包的容量。
  2. 每个包里的每种物品最多只有一件,但两个不同的包中可以存在相同的物品。
  3. 任意两个人,他们包里的物品清单不能完全相同。

在满足以上要求的前提下,所有包里的所有物品的总价值最大是多少呢?

输入格式:

第一行有三个整数:K、V、N。

第二行开始的 N 行,每行有两个整数,分别代表这件物品的体积和价值。

输出格式:

只需输出一个整数,即在满足以上要求的前提下所有物品的总价值的最大值。

样例输入:

2 10 5

3 12

7 20

2 4

5 6

1 1

样例输出:

57

数据范围:

总人数 K<=50。

每个背包的容量 V<=5000。

物品种类数 N<=200。

其它正整数都不超过 5000。

输入数据保证存在满足要求的方案。

时间限制:

1S

空间限制:

128M

题解

我发现我不会背包的拓展问题……这就是一个背包的k优解。

f(i,j)表示i体积,j优解。然后用双指针扫描转移即可。

#include<bits/stdc++.h>
#define co const
#define il inline
template<class T> T read() {
T x=0,w=1;
char c=getchar();
for(; !isdigit(c); c=getchar())if(c=='-') w=-w;
for(; isdigit(c); c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T>il T read(T&x) {
return x=read<T>();
}
using namespace std;
int k,v,n,ans,cnt,now[55];
int V[288],W[288],f[5008][55];
int main() {
read(k),read(v),read(n);
for(int i=0; i<=5000; i++)
for(int j=0; j<=50; j++)f[i][j]=-20021003;
f[0][1]=0;
for(int i=1; i<=n; i++)
read(V[i]),read(W[i]);
for(int i=1; i<=n; i++)
for(int j=v; j>=V[i]; j--) {
int c1=1,c2=1,cnt=0;
while(cnt<=k) {
if(f[j][c1]>f[j-V[i]][c2]+W[i])
now[++cnt]=f[j][c1++];
else now[++cnt]=f[j-V[i]][c2++]+W[i];
}
for(int c=1; c<=k; c++) f[j][c]=now[c];
}
for(int i=1; i<=k; i++) ans+=f[v][i];
printf("%d",ans);
}

新魔法药水

魔法师 DD 想给 MM 送一份生日礼物,可是他没有足够的金币。魔法娴熟的 DD 自然想到了利用自己高明的魔药配制技巧来多赚一些金币。

DD 一共知道 N 种魔药(以 1..N 编号),还掌握 M 种配制魔药的方法(以 1..M 编号)。他掌握的每种配制魔药的方法都可以简单表述如下:将若干种魔药各一瓶倒入坩埚内,用魔杖搅拌的同时施出一个特定的魔法,再经过适当浓缩,就可以得到一瓶新的魔药。

森林里有一家魔法商店,这里不仅出售各种魔药,同时也以比售价略低的价格收购各种魔药。DD 的如意算盘就是:首先用自己攒下的 V 个金币去魔法商店购买一些魔药作为原料,再用一天的时间在家努力地配制,最后把配制好的成品再卖给魔法商店。

然而,由于魔法修为的原因,DD 在一天之内最多只能施出 K 次魔法。

DD 想让你帮他算一算,他最多能够在这一天时间内赚到多少金币呢?

输入格式:

第一行有四个整数:N、M、V、K。

第二行开始的 N 行,每行有两个整数,第 i+1 行的两个整数分别表示第 i 种魔药的销售价和收购价。

第 N+2 行开始的 M 行,每行有若干个整数,表示 DD 知道的一种魔药配制方法。每行的格式都是这样的:第一个整数表示这种魔药配制方法可以得到的一瓶魔药成品的编号。下一个整数 n(n<N),表示这种配制方法需要 n 瓶原料。下面 n 个整数,表示这 n 瓶原料的编号。

输出格式:

只需输出一个整数,表示最多可以赚到金币的数量。

样例输入:

4 2 6 3

1 0

1 0

5 3

20 15

3 2 1 2

4 3 1 2 3

样例输出:

12

数据范围:

药水种类 N<=60。

配制方法数 M<=240。

初始的金币数 V<=1000。

每天可施的魔法数 K<=30。

时间限制:

1S

空间限制:

128M

题解

我想到了状态,但是没时间写了。f(i,j)表示第i个个物品用至多j次魔法的最小代价。然后我不知道怎么转移,想出来一个最短路。

先枚使用的魔法数,再枚魔法,这样进行转移才行。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
int n,m,V,cnt;
int tmp[61][31];//表示当前处理到i次用了j魔法的最低费用
int f[61][31];//表示第i件物品用j次魔法组成的最低费用
//用tmp更新f
int dp[1001][31];//表示当前花费i元用了j次魔法的最大收益
//用dp[i][j]-i更新答案
int v[61];//物品的售价
int id[250],sum[250];//每种魔法的成品和需要的原材料个数
vector<int>s[250];//每种魔法所需的原料是什么
int main()
{
memset(f,63,sizeof(f));
scanf("%d%d%d%d",&n,&m,&V,&cnt);
for(int i=1;i<=n;i++) scanf("%d%d",&f[i][0],&v[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&id[i],&sum[i]);
for(int j=1;j<=sum[i];j++)
{
int x; scanf("%d",&x);
s[i].push_back(x);
}
}
for(int i=1;i<=cnt;i++)
for(int j=1;j<=m;j++)
{
memset(tmp,63,sizeof(tmp));
tmp[0][0]=0;
int T=i-1;
for(int k=0;k<=T;k++)
for(int l=1;l<=sum[j];l++)
{
int x=s[j][l-1];
for(int a=0;a<=k;a++)
tmp[l][k]=min(tmp[l][k],tmp[l-1][k-a]+f[x][a]);
}
f[id[j]][i]=min(f[id[j]][i],tmp[sum[j]][T]);
for(int k=i;k<=cnt;k++) f[id[j]][k]=min(f[id[j]][k],f[id[j]][i]);
}
for(int i=1;i<=V;i++)
for(int j=0;j<=cnt;j++)
{
for(int k=1;k<=n;k++)
for(int l=0;l<=j;l++)
if(f[k][l]<=i)
dp[i][j]=max(dp[i][j],dp[i-f[k][l]][j-l]+v[k]-f[k][l]);
}
printf("%d",dp[V][cnt]);
return 0;
}

test20190803 夏令营NOIP训练19的更多相关文章

  1. test20190805 夏令营NOIP训练20

    100+0+0=100,由于第二题写挂rank 1就没了 山 xyz现在站在一个斜坡面前 这个斜坡上依次排布这n座山峰,xyz打算爬上其中的一座 因为xyz体力不好,所以他只能爬上最矮的一座山 又因为 ...

  2. test20190802 夏令营NOIP训练18

    今天的题很有难度啊.然而我10:40才看题-- 高一学堂 在美丽的中山纪念中学里面,有一座高一学堂.所谓山不在高,有仙则名:水不在深,有龙则灵.高一学堂,因为有了yxr,就成了现在这个样子 = =. ...

  3. test20190731 夏令营NOIP训练16

    0+90+0=90.我只挑了T2做. 连接格点 有一个M行N列的点阵,相邻两点可以相连.一条纵向的连线花费一个单位,一条横向的连线花费两个单位.某些点之间已经有连线了,试问至少还需要花费多少个单位才能 ...

  4. test20190729 夏令营NOIP训练14

    40+100+0=140. 基因光线 黑大帅统治古古怪界后,一直在玩一种很奇葩的游戏.在一个二维平面上,他先复制了n个小A,把他们放在不同的位置,然后射出一条ax+by+c=0的基因光线,宽度为d,即 ...

  5. 9.19[XJOI] NOIP训练37

    上午[XJOI] NOIP训练37 T1 同余方程 Problem description 已知一个整数a,素数p,求解 $x^{2}\equiv a(mod p) $ 是否有整数解 Solution ...

  6. Noip 训练指南

    目录 Noip 训练指南 图论 数据结构 位运算 期望 题解 Noip 训练指南 目前完成 \(4 / 72\) 图论 [ ] 跳楼机 [ ] 墨墨的等式 [ ] 最优贸易 [ ] 泥泞的道路 [ ] ...

  7. 2018.10.19 NOIP训练 变化的序列(线性dp)

    传送门 f[i][j]f[i][j]f[i][j]表示后iii个对答案贡献有jjj个a的方案数. 可以发现最后a,ba,ba,b的总个数一定是n∗(n−1)/2n*(n-1)/2n∗(n−1)/2 因 ...

  8. 2018.10.19 NOIP训练 桌子(快速幂优化dp)

    传送门 勉强算一道dp好题. 显然第kkk列和第k+nk+nk+n列放的棋子数是相同的. 因此只需要统计出前nnn列的选法数. 对于前mmm%nnn列,一共有(m−1)/n+1(m-1)/n+1(m− ...

  9. 2018.10.19 NOIP训练 游戏问题(分组背包)

    传送门 分组背包经典问题. 令f[i][j]f[i][j]f[i][j]表示前iii组花费为jjj的最优值. g[i][j]g[i][j]g[i][j]表示前iii组,第iii组已经支付了平台费用的最 ...

随机推荐

  1. socket-01

     对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端

  2. 从一个案例窥探ORACLE的PASSWORD_VERSIONS

    1.环境说明 ORACLE 客户端版本 11.2.0.1 ORACLE 服务端版本 12.2.0.1 2.异常现象 客户端(下文也称为Cp)访问服务端(Sp),报了一个错误: Figure 1 以错误 ...

  3. 逸鹏说道公众号福利:逆天常用的一些谷歌浏览器插件V1.3

    插件导出:http://www.cnblogs.com/dunitian/p/5426552.html 插件导入:https://www.cnblogs.com/dotnetcrazy/p/97537 ...

  4. Vue问题汇总

    Vue——父子组件间异步动态获取数据传递数据时,子组件获取不到值或者延时获取: 通过watch解决:https://blog.csdn.net/where_slr/article/details/99 ...

  5. Jenkins+TestNG+gitlab+maven持续集成

    准备工作: 1.安装Jenkins 网上有jenkins安装配置教程 2.jenkins配置 2.1全局工具配置 配置JDK JDK别名:名称可以随意,但是要方便识别 JAVA_HOME:centos ...

  6. 【原创】C++STL multiset

    资料来源:官方文档 multiset是一个按照特定排序储存元素的容器,多个元素可以有相同的值.元素的值即为其本身的键值.multiset中的值无法修改,可插入删除.常用于实现二叉树. 定义一个mult ...

  7. python学习-65 继承2-子类中调用父类的方法

    子类中调用父类的方法 1.子类继承了父类的方法,然后想进行修改,那么就需要在子类中调用父类的方法. 2.方法一:父类名 class School: Country = 'china' def __in ...

  8. 44 容器(三)——ArrayList索引相关方法

    方法都比较简单,这里列出来即可: add(index,ele) //忘制定下标插入元素 add(ele) addAll(Collection <C> c) 泛型必须与调用add的泛型保持一 ...

  9. THUPC&CTS&APIO2019:Far Away

    流水账~ THUPC nmdwsmduliu! THUPC Day -INF~Day -2 大概就是自己做题和每周两次的考试,lsy和fcw两个外校的来吊打我们qwqqq THUPC Day -1 Z ...

  10. font-svg

    https://fontawesome.com/ http://www.fontawesome.com.cn/cheatsheet/ http://www.iconfont.cn/ string lj ...