NOIP模拟测试18(T3待更新)
T1:
直接模拟,详见代码注释。
复杂度$O(NM)$。
Code:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int N=;
const int M=;
int n,m,tot=;
int a[N][N];
int u[M],d[M],l[M],r[M],bl[M];//上下左右边界及水箱编号
vector<int> v[M],bx[N],by[N];//v做临接表,bx和by存储水箱边界
int get()
{
char c=getchar();
while(c!='.'&&c!='-'&&c!='|'&&c!='+'&&(c<''||c>''))
c=getchar();
if(c>=''&&c<='') return c-'';//水箱编号
else if(c=='-') return -;//横向管道
else if(c=='|') return -;//纵向管道
else if(c=='+') return -;//管道转折,其实和前两个一样,可以不做区分
else return -;//空格子
}
void find(int id,int x,int y)//二分查找水箱边界
{
int xx,yy;
yy=lower_bound(bx[x].begin(),bx[x].end(),y)-bx[x].begin();
r[id]=bx[x][yy];l[id]=bx[x][yy-];
xx=lower_bound(by[y].begin(),by[y].end(),x)-by[y].begin();
d[id]=by[y][xx];u[id]=by[y][xx-];
}
void clean(int id)//将整个水箱的区域都标上该水箱的编号
{
for(int i=u[id];i<=d[id];i++){
for(int j=l[id];j<=r[id];j++)
a[i][j]=id;
}
}
int walk(int x,int y)//沿管道寻找
{
a[x][y]=-;
if(a[x+][y]>) return a[x+][y];//水箱成树形
if(a[x+][y]<=-&&a[x+][y]>=-) return walk(x+,y);
if(a[x][y+]<=-&&a[x][y+]>=-) return walk(x,y+);
if(a[x][y-]<=-&&a[x][y-]>=-) return walk(x,y-);
}
void work(int id)
{
for(int i=d[id];i>=u[id];i--){//水必定先进入靠下的水箱,所以从下到上枚举
if(a[i][l[id]-]<=-&&a[i][l[id]-]>=-)
v[id].push_back(walk(i,l[id]-));
if(a[i][r[id]+]<=-&&a[i][r[id]+]>=-)
v[id].push_back(walk(i,r[id]+));
}
}
void print(int id)//按水箱高度递归输出
{
for(int i=;i<v[id].size();i++)
print(v[id][i]);
printf("%d\n",id);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
a[i][j]=get();//获取格子类型
if(a[i][j]>=&&a[i][j-]>=){//注意水箱编号大于一位的情况
a[i][j]+=*a[i][j-];//用类似快读的思想
a[i][j-]=-;//每个水箱内只能有一个数字
}
if(a[i][j]>=-&&a[i][j]<=-){//将水箱边界存入
bx[i].push_back(j);
by[j].push_back(i);
}
}
}
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(a[i][j]>=){
bl[++tot]=a[i][j];//记录水箱编号,水箱编号可能不连续
find(a[i][j],i,j);//寻找水箱边界
}
}
}
for(int i=;i<=tot;i++) clean(bl[i]);
for(int i=;i<=tot;i++) work(bl[i]);
print();
return ;
}
T1
T2:
DP好题,不过暴力也能A。
题目大意:一条线上N个点,共有精灵M个,时间为一时位于K,精灵都有价值,但一段时间后会消失,求收获的最大权值。
DP(正解):
搜索(暴力):
暴力压正解,我就不说什么了…………
下面说DP:搜索可以自己想
设DP数组f[i][j][k],表示i~j已经走过,目前位于i的最大值。
由于抓取精灵不需要时间,而且权值均为正,所以每次遇到精灵一定会抓。
先对精灵按照坐标排序。
将精灵的坐标连同起始点离散,初始化为负无穷,时间为一时起点处权值赋为0。
这是一个区间DP,先枚举时间,然后枚举区间长度,再枚举左端点,算出右端点。
然后我们就可以开心地DP了:
i为时间,L为左端点,R为右端点,val代表精灵的权值,p代表精灵的位置,t为精灵消失的时间。
f[L-1][R][i+1]=max(f[L-1][R][i+1],f[L][R][i]+val[L-1]) (i+p[L]-p[L-1]<=t[L-1])
f[L-1][R][i+1]=max(f[L-1][R][i+1],f[L][R][i]) (i+p[L]-p[L-1]>t[L-1])
f[R+1][L][i+1]=max(f[R+1][L][i+1],f[R][L][i]+val[R+1]) (i+p[R+1]-p[R]<=t[R+1])
f[R+1][L][i+1]=max(f[R+1][L][i+1],f[R][L][i]) (i+p[R+1]-p[R]>t[R+1])
f[R+1][L][i+1]=max(f[R+1][L][i+1],f[L][R][i]+val[R+1]) (i+p[R+1]-p[L]<=t[R+1])
f[R+1][L][i+1]=max(f[R+1][L][i+1],f[L][R][i]) (i+p[R+1]-p[L]>t[R+1])
f[L-1][R][i+1]=max(f[L-1][R][i+1],f[R][L][i]+val[L-1]) (i+p[R]-p[L-1]<=t[L-1])
f[L-1][R][i+1]=max(f[L-1][R][i+1],f[R][L][i]) (i+p[R]-p[L-1]>t[L-1])
后四行的转移方程代表从区间的一头走到另一头再扩展区间,不能丢。
起点算作一只贡献为0的精灵,方便判断。
注意判断在该时间内精灵是否已消失。
DP过程中不断对ans取max,最后的max即为答案。
共有M只精灵,时间的最大值为T。
时间复杂度$O(M^2T)$
Code:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=;
const int M=;
const int inf=;
int n,k,m,t=,ans=;
int s[M],dp[M][M][N];
struct point {
int a,b,c;
}p[M];
bool comp(const point a1,const point a2)
{
return a1.a<a2.a;
}
int main()
{
scanf("%d%d%d",&n,&k,&m);
for(int i=;i<=m;i++){
scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
t=max(p[i].c,t);
}
p[++m].a=k;
sort(p+,p+m+,comp);
for(int i=;i<=t;i++){
for(int j=;j<=m;j++){
for(int l=;l<=m-j+;l++){
int r=l+j-;
dp[l][r][i]=dp[r][l][i]=-inf;
}
}
}
for(int i=;i<=m;i++){
s[i]=p[i].a;p[i].a=i;
if(s[i]==k)
dp[i][i][]=p[i].b;
}
for(int i=;i<=t;i++){
for(int j=;j<=m;j++){
for(int l=;l<=m-j+;l++){
int r=l+j-;
if(dp[l][r][i]>=){
if(l>=){
int ti=i+s[l]-s[l-];
if(ti<=p[l-].c)
dp[l-][r][ti]=max(dp[l-][r][ti],dp[l][r][i]+p[l-].b);
else
dp[l-][r][ti]=max(dp[l-][r][ti],dp[l][r][i]);
ans=max(ans,dp[l-][r][ti]);
}
if(r<=m-){
int ti=i+s[r+]-s[l];
if(ti<=p[r+].c)
dp[r+][l][ti]=max(dp[r+][l][ti],dp[l][r][i]+p[r+].b);
else
dp[r+][l][ti]=max(dp[r+][l][ti],dp[l][r][i]);
ans=max(ans,dp[r+][l][ti]);
}
}
if(dp[r][l][i]>=){
if(l>=){
int ti=i+s[r]-s[l-];
if(ti<=p[l-].c)
dp[l-][r][ti]=max(dp[l-][r][ti],dp[r][l][i]+p[l-].b);
else
dp[l-][r][ti]=max(dp[l-][r][ti],dp[r][l][i]);
ans=max(ans,dp[l-][r][ti]);
}
if(r<=m-){
int ti=i+s[r+]-s[r];
if(ti<=p[r+].c)
dp[r+][l][ti]=max(dp[r+][l][ti],dp[r][l][i]+p[r+].b);
else
dp[r+][l][ti]=max(dp[r+][l][ti],dp[r][l][i]);
ans=max(ans,dp[r+][l][ti]);
}
}
}
}
}
printf("%d\n",ans);
return ;
}
T2
建议搜索AC的人打一遍DP,毕竟正经NOIP数据是不会这么水的。
NOIP模拟测试18(T3待更新)的更多相关文章
- 2019.8.12 NOIP模拟测试18 反思总结
写个博客总是符合要求的对吧 回来以后第一次悄悄参加考试,昨天全程围观… 然后喜提爆炸120分wwwwwwwww T1用了全机房最慢的写法,导致改掉死循环T掉的一个点以后还是死活过不了最后一个点.T2全 ...
- noip模拟测试18
打开比赛第一眼--超级树? 点开--原题 百感交集-- 欣喜于发现是半年前做过两遍的原题 紧张于如果A不了比较尴尬 绝望于发现根本不会做了 瞟了一眼t1,瞅了一眼t2,嗯--开始搞t3 10分钟打完暴 ...
- NOIP模拟测试18「引子·可爱宝贝精灵·相互再归的鹅妈妈」
待补 引子 题解 大模拟,注意细节 代码1 #include<bits/stdc++.h> using namespace std; int n,m;char a[1005][1005]; ...
- NOIP模拟测试17&18
NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
- 「题解」NOIP模拟测试题解乱写I(29-31)
NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...
随机推荐
- configure: error: libXpm.(a|so) not found
libXpm-devel明明已经安装过了,libXpm.so之类的也都存在,但是还是一直报这个问题, 百度了很长时间,终于找到了: configure一般的搜索编译路径为/usr/lib/下,因为ph ...
- BZOJ 4555(第二类斯特林数+NTT)
传送门 解题思路 数学题,推式子.求\(f(n)=\sum\limits_{i=0}^n\sum\limits_{j=0}^iS(i,j)2^jj!\) 首先可以把\(j\)往前提: \[f(n)=\ ...
- windows环境下安装pymysql(操作带图)
在windows环境下安装pymysql,首先要找到python的安装位置,如果在c盘,启动cmd的时候,要获取管理员权限. 具体步骤,一,管理员模式启动cmd.在箭头指定位置,搜索cmd,出现快捷方 ...
- 移动无线测试技能图谱skill-map
# 移动无线测试技能图谱 ## 常用IDE- Android * ADT * Android Studio- iOS * Xcode- Common * Atom * Sublime Text * V ...
- 在pycharm中切换python版本的方法
转载自:https://blog.csdn.net/sgfmby1994/article/details/77876873 目前,python2和python3都有很重要的意义,所以,我们经常会在电脑 ...
- 数据库的基本使用(C#语言)
目录 insert select 的使用 delete update 更新 Like模糊查询 Order 排序 GETDATA() 聚合函数:MAX,MIN,AVG,SUM,COUNT Max COU ...
- git的使用(本地版本库)
1. 创建版本库 1.1 创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录: 1.2通过git init命令把这个目录变成Git可以管理的仓库(git进入空目录的路径) $ git i ...
- 在doker上的python安装及环境部署
python环境部署 我们今天学习的内容是如何将Django项目部署到linux服务器上,我们部署的linux系统是centos7首先,我们先在linux上搭建我们的Python3环境: 在这里首先强 ...
- 数据持久化之嵌入式数据库 SQLite(三)
阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680 SQLite 是 D. Richard Hipp 用 C 语言编写的开源 ...
- adb基本操作
用途 命令 备注 安装app adb install xxx.apk -l 锁定该应用程序-r 替换已存在的应用程序,也就是说强制安装-t 允许测试包-s 把应用程序安装到sd卡上-d 允许进行降级安 ...