洛谷10月月赛Round.3
Rank11:260=60+100+100
P2409 Y的积木
题目背景
Y是个大建筑师,他总能用最简单的积木拼出最有创意的造型。
题目描述
Y手上有n盒积木,每个积木有个重量。现在他想从每盒积木中拿一块积木,放在一起,这一堆积木的重量为每块积木的重量和。现在他想知道重量和最小的k种取法的重量分别是多少。(只要任意更换一块积木,就视为一种不同的取法。如果多种取法重量总和一样,我们需要输出多次。)
输入输出格式
输入格式:
第一行输入两个整数,n,k,意义如题目所描述。
每组数据接下来的n行,第一个整数为mi,表示第i盒积木的数量,在同一行有mi个整数,分别表示每个积木的重量。
输出格式:
一行,重量最小的k种取法的重量,要求对于每个数据,从小到大输出
输入输出样例
3 10
4 1 3 4 5
3 1 7 9
4 1 2 3 5
3 4 5 5 6 6 7 7 7 7
说明
对于30%的数据:2<=mi<=10,1<=n<=10
对于50%的数据:2<=mi<=50,1<=n<=50
对于100%的数据:2<=mi<=100,1<=n<=100,1<=k<=10000,每个积木的重量为不超过100的正整数,所有mi的积大于等于k。本题不卡常。
先想的分组背包前k优值问题,可以把01背包的变形一下,二路归并改多路归并
后发现每个组就选一个,直接多路归并就行了
然后........就60分了,后面的全T了,复杂度O(n*k*logk),k太大
正解:f[i][j]表示前i组重量为j的方案数,O(m[i])转移,复杂度O(n*最大重量*m),本题重量很小
1.这样的DP用刷表法快;2.注意打印解的时候
//60 多路归并
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N=,M=1e4+;
typedef long long ll;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int n,k,m[N],w[N][N];
int f[M];
struct data{
int s,p;//s=f[a]+w[m][p]
data(int x=,int y=):s(x),p(y){}
bool operator <(const data &r)const{return s>r.s;}
};
void merge(int w[],int m){
priority_queue<data> q;
for(int i=;i<=k;i++){
if(f[i]!=-) q.push(data(f[i]+w[],));
//printf("push %d %d %d\n",i,f[i],w[i]);
else break;
}
for(int i=;i<=k&&!q.empty();i++){
data now=q.top();q.pop();
int s=f[i]=now.s;
int p=now.p;
if(p+<=m) q.push(data(s-w[p]+w[p+],p+));
//printf("now %d %d\n",s,p);
}
}
void dp(){
memset(f,-,sizeof(f));
f[]=;
for(int i=;i<=n;i++) merge(w[i],m[i]);
}
int main(int argc, const char * argv[]) {
n=read();k=read();
for(int i=;i<=n;i++){
m[i]=read();
for(int j=;j<=m[i];j++) w[i][j]=read();
sort(w[i]+,w[i]++m[i]);
}
dp();
for(int i=;i<=k;i++) printf("%d ",f[i]);
return ;
}
//AC 递推
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N=,M=;
typedef long long ll;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int n,sum,v=,m[N],w[N][N];
int f[N][M];void dp(){
f[][]=;
for(int i=;i<=n;i++)
for(int j=;j<=v;j++) if(f[i-][j])
for(int k=;k<=m[i];k++)
f[i][j+w[i][k]]+=f[i-][j];
}
int main(int argc, const char * argv[]) {
n=read();sum=read();
for(int i=;i<=n;i++){
m[i]=read();
for(int j=;j<=m[i];j++) w[i][j]=read();
sort(w[i]+,w[i]++m[i]);
}
dp();
for(int i=;;i++){
if(f[n][i]>=sum){
for(int j=;j<=sum;j++) printf("%d ",i);
break;
}else{
for(int j=;j<=f[n][i];j++) printf("%d ",i);
sum-=f[n][i];
}
}
return ;
}
P1371 NOI元丹
题目描述
小A打算开始炼NOI元丹(什么鬼),据说吃了可以提高NOI时的成绩。
是这么练的。元丹有三种元核,'N','O','I'。现有很多个这样原核,按顺序排成一行。炼元丹时,从左往右分别挑出'N','O','I'三个原核吞下。
现在他关心,有几种服用方式……且慢!
他觉得服用方式太少,以至于不能成仙。所以他可以通过某个途径,得到'N','O','I'的三种原核中的任意一个,至于哪一种由他决定。然后他将获得这个原核的插入到这一排原核中的任意位置(包括最前最后)。
现在你要知道,新的元核序列中能有多少种'N','O','I'的取出方式。子串的字母并不要求连续。
输入输出格式
输入格式:
第一行,一个整数N,表示字符串的长度。
第二行,一行字符串,里面只有只有'N','O','I'三种字母。
输出格式:
表示出最多可以提炼出来的NOI元丹的方案种数。
输入输出样例
5
NOIOI
6
说明
样例解释
他可以获取一个N元核,加到最前面。
NNOIOI | NNOIOI | NNOIOI | NNOIOI | NNOIOI | NNOIOI
~ ~~ | ~ ~ ~ | ~ ~~ | ~~~ | ~~ ~ | ~ ~~
30%的数据N<=200
50%的数据N<=2000
100%的数据3<=N<=100000
很容易想到序列DP
f[i][0/1/2]表示i之前N NO NOI个数,d[i][0/1/2]表示i之后I OI NOI个数
可以很快计算在i到i+1之间加字母的贡献
tn=sum+d[i+1][1],ti=sum+f[i][1],to=sum+d[i+1][0]*f[i][0]
PS:其实加N的话一定在开始处,加I的话一定在结尾处最优
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N=1e5+;
typedef long long ll;
int n;
char s[N];
ll f[N][],d[N][],sum=,ans=;
void dp(){
for(int i=;i<=n;i++){
f[i][]=f[i-][];
if(s[i]=='N') f[i][]++;
f[i][]=f[i-][];
if(s[i]=='O') f[i][]+=f[i-][];
f[i][]=f[i-][];
if(s[i]=='I') f[i][]+=f[i-][];
//printf("f %d %d %d %d\n",i,f[i][0],f[i][1],f[i][2]); int ti=i;i=n-i+;
d[i][]=d[i+][];
if(s[i]=='I') d[i][]++;
d[i][]=d[i+][];
if(s[i]=='O') d[i][]+=d[i+][];
d[i][]=d[i+][];
if(s[i]=='N') d[i][]+=d[i+][]; i=ti;
}
sum=f[n][];
for(int i=;i<=n;i++){
ll tn=sum+d[i+][],ti=sum+f[i][],to=sum+d[i+][]*f[i][];
ans=max(ans,max(tn,max(to,ti)));
//printf("t %d %d %d %d\n",i,tn,to,ti);
}
}
int main(int argc, const char * argv[]){
scanf("%d%s",&n,s+);
dp();
printf("%lld",ans);
return ;
}
P1710 地铁涨价
题目背景
本题开O2优化,请注意常数
题目描述
博艾市除了有海底高铁连接中国大陆、台湾与日本,市区里也有很成熟的轨道交通系统。我们可以认为博艾地铁系统是一个无向连通图。博艾有N个地铁站,同时有M小段地铁连接两个不同的站。
地铁计价方式很简单。从A站到B站,每经过一小段铁路(连接直接相邻的两个点的一条边),就要收取1博艾元。也就是说,从A站到B站,选择的路径不一样,要价也会不同。
我们认为凡华中学在1号地铁站。学生们通过地铁通勤,他们当然知道选择最短路来坐车的话,票价最便宜。
然而博艾地铁公司经营不善,一直亏损,于是他们打算提价。提价一次就是将一小段铁路原来收费1元改收2元。同一小段的铁路不会多次提价。他们打算提价Q次。
学生们知道,如果他们到学校的一条最短路径中的一小段提价了,可以改变路径,使总票价不变。然而随着一条一条的铁路被提价,当居住在某个站附近的学生发现,提价后,没有任何一种方案可以从家到学校的费用和初始费用相等时,就会不满。
现在地铁公司希望知道,对于每一次涨价,有多少个站,学生会因为涨价而不满呢?
输入输出格式
输入格式:
第一行为三个整数N,M,Q。
接下来M行,每行2个整数ai,bi,表示第i条铁路连接的两个站。i表示铁路编号。
接下来Q行,每行一行整数rj,表示每次涨价的铁路编号。
输出格式:
Q行。每行一个整数表示不满的车站数量。
输入输出样例
5 6 5
1 2
1 3
4 2
3 2
2 5
5 3
5
2
4
1
3
0
2
2
4
4
说明
【样例解释】
次数 车站2 车站3 车站4 车站5
初始 1 1 2 2
1 1 1 2 2
2 1 2 2 3
3 1 2 2 3
4 2 2 3 3
5 2 2 4 3
【数据范围】
对于20%的数据 N≤100, Q≤30
对于40%的数据 Q≤30
对于70%的数据 正确的输出结果中,不会有超过50种不一样的整数(数据范围剧透解法系列)
对于100%的数据 N≤100000, Q≤M≤200000
可以发现涨价后不可能在经过那里
增加一个涨价时间t,其实就是要找出每个车站到1的最短路中t最小的铁路的t最大值(因为可能有多条最短路)
刚做了NOIP2009最优贸易,一样的思想啊用SPFA即可
一些理解:
DP可以处理DAG
spfa可以处理带环的(dij也可以,但只能是最短路问题)
spfa有点像DP,计算一个图上的状态,只不过一个状态可能被计算多次(因为有环)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N=1e5+,M=2e5+,INF=1e9;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
}
int n,m,Q,u,v;
struct edge{
int v,ne,t;//time of raise
edge(int a=INF):v(),ne(),t(a){}
}e[M<<];
int h[N],cnt=;
void ins(int u,int v){
cnt++;
e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
cnt++;
e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}
int q[N],head=,tail=,inq[N],d[N];
struct node{
int id,t;
node(int a=,int b=):id(a),t(b){}
bool operator <(const node &r)const{return t<r.t;}
}a[N];
inline void lop(int &x){if(x==N-) x=;}
void spfa(){
for(int i=;i<=n;i++) a[i].id=i,d[i]=INF;
q[tail++]=;
a[].t=INF;d[]=;
while(head!=tail){
int u=q[head++];inq[u]=;lop(head);
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(d[v]>d[u]+){
d[v]=d[u]+;
a[v].t=min(a[u].t,e[i].t);
if(!inq[v]){q[tail++]=v;inq[v]=;lop(tail);}
}else if(d[v]==d[u]+)
a[v].t=max(a[v].t,min(a[u].t,e[i].t));
}
}
} int main(int argc, const char * argv[]) {
n=read();m=read();Q=read();
for(int i=;i<=m;i++){u=read();v=read();ins(u,v);}
for(int i=;i<=Q;i++){u=read();e[*u-].t=e[*u].t=i;}
spfa();
sort(a+,a++n);
int p=,ans=;
//for(int i=1;i<=n;i++) printf("node %d %d\n",a[i].id,a[i].t);
//for(int i=1;i<=2*m;i++ ) printf("edge %d %d %d\n",i,e[i].v,e[i].t);
for(int i=;i<=Q;i++){
while(a[p].t<=i) ans++,p++;
printf("%d\n",ans);
}
return ;
}
洛谷10月月赛Round.3的更多相关文章
- 洛谷10月月赛Round.1| P3398 仓鼠找sugar[LCA]
题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c) ...
- 洛谷10月月赛Round.1| P3400 仓鼠窝[单调栈]
题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子矩阵!(实际上就是有 ...
- 洛谷10月月赛Round.1| P3399 丝绸之路 [DP]
题目背景 张骞于公元前138年曾历尽艰险出使过西域.加强了汉朝与西域各国的友好往来.从那以后,一队队骆驼商队在这漫长的商贸大道上行进,他们越过崇山峻岭,将中国的先进技术带向中亚.西亚和欧洲,将那里的香 ...
- 【LGR-054】洛谷10月月赛II
[LGR-054]洛谷10月月赛II luogu 成功咕掉Codeforces Round #517的后果就是,我\(\mbox{T4}\)依旧没有写出来.\(\mbox{GG}\) . 浏览器 \( ...
- 洛谷10月月赛II题解
[咻咻咻] (https://www.luogu.org/contestnew/show/11616) 令人窒息的洛谷月赛,即将参加NOIp的我竟然只会一道题(也可以说一道也不会),最终145的我只能 ...
- 洛谷11月月赛round.1
太感动了#2 thwfhk 240 (801ms) 100 100 40 又一张明信片,话说10月的怎么还没收到 P2246 SAC#1 - Hello World(升级版) 题目背景 一天, ...
- 【LGR-061】洛谷10月月赛 II & X Round 4 Div.1&Div 2
X Round的题目质量还是一如既往的高 然而每次周末我都要写作业没法用心打233主要是被陈指导放了鸽子 占坑代填(最近坑开的有点多)
- 洛谷11月月赛round.2
P3414 SAC#1 - 组合数 题目背景 本题由世界上最蒟蒻最辣鸡最撒比的SOL提供. 寂月城网站是完美信息教室的官网.地址:http://191.101.11.174/mgzd . 题目描述 辣 ...
- 【LGR-060】洛谷10月月赛 I div.1&div.2
Preface 一边打一边写作文打的像shit,T2失智严重特判错了233 Orz Div1 Rank2的foreverlastnig聚聚,顺便说一句显然Luogu的比赛质量比以往显著提高了啊 以下题 ...
随机推荐
- sql 中的Bulk和C# 中的SqlBulkCopy批量插入数据 ( 回顾 and 粗谈 )
通常,我们会对于一个文本文件数据导入到数据库中,不多说,上代码. 首先,表结构如下. 其次,在我当前D盘中有个文本文件名为2.txt的文件. 在数据库中,可以这样通过一句代码插入. Bulk in ...
- AJAX与PHP(PHP笔记)--动态验证用户名
在PHP基础的学习过程中经常会遇到对页面的局部刷新. 比如说,我们在填写用户名的同时,对数据库中的信息进行验证,检查是否充分. 这时就要用到AJAX实现页面的动态加载. 下面例子是简单的PHP与AJA ...
- PHP运算符
运算符 PHP运算符可以根据操作数的个数分为一元运算符.二元运算符.三元运算符.一元运算符例如!(取反运算符)或++(加一运算符),PHP支持的大多数运算符都是这种二元运算符,例如+.-.*./等算数 ...
- zookeeper集群
0,Zookeeper基本原理 ZooKeeper集群由一组Server节点组成,这一组Server节点中存在一个角色为Leader的节点,其他节点都为Follower.当客户端Client连接到Zo ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(24)-权限组的设计和实现(附源码)(终结)
ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 (2):数据库访问层的设计Demo (3):面向接口编程 (4 ):业务逻辑层的封装 ...
- 学习zepto.js(对象方法)[2]
今天来说下zepto那一套dom操作方法, prepend,append,prependTo,appendTo,before,after,insertBefore,insertAfter; 按着从内到 ...
- SharePoint 2013 Excel Services ECMAScript 示例之明日限行
前言:最近遇到一个“明日限行”的功能,北京的交通啊,这个不在今天讨论范围内,暂不吐槽,想想代码开发,还要写WebPart部署,很麻烦,而且部署服务器,需要领导审批,想绕过这个麻烦事儿,就想到客户端了, ...
- 发布有礼!2015 Autodesk程序商店有奖发布活动拉开序幕
您是不是有希望您的 Autodesk 产品应用程序有更多的用户?您是不是正在寻求更广阔的市场机会?您是不是在激荡人心的云时代大潮中有许多奇思妙想没有小试身手? 来吧,来参加Autodesk应用程序发布 ...
- Linux0.11内核--加载可执行二进制文件之2.change_ldt
前面分析完了copy_strings函数,这里来分析另一个注意的函数change_ldt. 先来看调用处: // 根据a_text 修改局部表中描述符基址和段限长,并将参数和环境空间页面放置在数据段末 ...
- IOS 杂笔-17(堆区栈区等)
栈区(stack):由系统自动分配,一般存放函数参数值.局部变量的值等.由编译器自动创建与释放.其操作方式类似于数据结构中的栈,即后进先出.先进后出的原则. 例如:在函数中申明一个局部变量int b; ...