题解 [AHOI2017/HNOI2017]大佬
注意到题面里n很小,有\(n\leq100\)
考虑联系n的实际意义
n是你在大佬手中能活的天数
题面颇富深意
好了不闹了
n很小,对于\(40\%\)的数据,爆搜即可
考场上靠这个骗了40pts
对于满分做法
我是考完看了题解才开始写的
然而题解貌似写麻烦了
首先对大佬的伤害与特定日期无关,只与分配给蓄力/伤害的天数有关
所以先dp一下在保证不死的前提下最多能留出多少天输出
我们需要知道能否打出一个特定伤害
所以尝试爆搜一下,得到花费\(d\)时间可以打出的伤害\(f\)
回看题面,题面可转化为「对于每个\(c_i\),问是否能构造出一种花费\(d\)天的怼大佬方案,使伤害\(f\leqslant c_i\)且\(f+md-d\geqslant c_i\)」,这里md为最多输出天数
已知所有的\(f\)和\(d\),如何验证方案?
只怼一次或不怼\(O(n)\)扫一遍就好
怼两次,则需满足
(1)\(f_1+f_2 \leqslant c_i\)
(2)\(f_1+f_2+md-d_1-d_2 \geqslant c_i\)
(3)\(d_1+d_2 \leqslant md\)
将(2)移项,得\(f_1+f_2 \geqslant c_i+(d_1+d_2-md)\)
则满足(1)(2)必定同时满足(3)
仍然是区间取值问题,尝试将序列排序后固定一个端点
\(f_1, d_1, md\)固定,则check \(f_1+d_1+md+(f_2-d_2)_{max}\)是否\(\geqslant c_i\)即可
注意到这里\(f_1+f_2\)具有单调性,即(已由小到大排序过)对于\(f_i\)不可行的\(f_2\),对于\(f_{i+1}\)同样不可行
所以采用双指针,每个左端点继承上个左端点的右端点进行扫描
时间复杂度就优化到了\(O(n)\)
对于那部分爆搜:
直接爆搜时间复杂度显然不对,考虑进行剪枝
这里出现了我以前没应用过的剪枝方法:利用\(hash\)进行判重
显然爆搜时对于相同的参数,所得结果应该是一样的,否则请先调试
那么把整个参数表hash掉,可完成记忆化
不过在这道题里更显著的应用是,
对于一个相同的f,我们只关心最小用时d,所以可以再开个hash表存
根据题解,我们可以采用bfs而不是dfs,因为bfs满足最先搜到某个f时天数一定是最小的,可以利用此性质优化hash表
p.s. 这个双指针的思路着实清奇
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 110
#define MAXN 500010
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m, mc;
int a[N], w[N], c[25], md, size, mblood, cnt;
int dp[N][N];
struct plan{int d, f; inline void build(int d_, int f_) {d=d_; f=f_;} plan(int d_, int f_):d(d_),f(f_){} plan(){}}met[MAXN];
inline bool operator == (plan a, plan b) {return a.f==b.f&&a.d==b.d;}
inline bool operator < (plan a, plan b) {return a.f<b.f;}
struct ele{int d, f, l; ele(){} ele(int d_, int f_, int l_):d(d_),f(f_),l(l_){} inline void build(int d_, int f_, int l_){d=d_; f=f_; l=l_;}};
inline bool operator == (ele a, ele b) {return a.f==b.f&&a.d==b.d&&a.l==b.l;}
struct hush_map1{
static const int SIZE=101000;
int size, head[SIZE];
hush_map1():size(0){memset(head, 0, sizeof(head));}
struct node{int dat, next;}e[SIZE*10];
inline bool operator [] (int q) {
ll t = q%SIZE;
for (int i=head[t]; i; i=e[i].next)
if (e[i].dat==q) return 1;
node* k=&e[++size]; k->dat=q; k->next=head[t]; head[t]=size;
return 0;
}
}mp1;
struct hush_map2{
static const int SIZE=1010000;
int size, head[SIZE];
hush_map2():size(0){memset(head, 0, sizeof(head));}
struct node{ele p; int next;}e[SIZE*10];
inline bool operator [] (ele q) {
ll t = (1ll*(q.d<<7)*q.f+q.l)%SIZE;
for (int i=head[t]; i; i=e[i].next)
if (e[i].p==q) return 1;
if (size<SIZE) {node* k=&e[++size]; k->p=q; k->next=head[t]; head[t]=size;}
return 0;
}
}mp2;
struct hush_c{
static const int SIZE=1000;
int size, head[SIZE];
hush_c():size(0){memset(head, 0, sizeof(head));}
struct node{int p; bool vis; int next;}e[SIZE<<1];
inline void operator [] (int q) {
int t=q%SIZE;
for (int i=head[t]; i; i=e[i].next)
if (e[i].p==q) {
if (!e[i].vis) e[i].vis=1,++cnt;
break;
}
}
void add(int q) {
int t=q%SIZE;
node* k=&e[++size]; k->p=q; k->vis=0; k->next=head[t]; head[t]=size;
}
bool query(int q) {
int t=q%SIZE;
for (int i=head[t]; i; i=e[i].next)
if (e[i].p==q)
return e[i].vis;
puts("error");
}
}test;
void checkout() {for (int i=1; i<=m; ++i) printf("%d\n", test.query(c[i]));}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
//cout<<double(sizeof(met)+sizeof(mp1.head)+sizeof(mp1.e))/1024/1024<<endl;
n=read(); m=read(); mc=read();
for (int i=1; i<=n; ++i) a[i]=read();
for (int i=1; i<=n; ++i) w[i]=read();
for (int i=1; i<=m; ++i) c[i]=read(), mblood=max(mblood, c[i]), test.add(c[i]);
for (int i=n; i; --i)
for (int j=a[i]; j<=mc; ++j)
dp[i][j] = max(max(dp[i+1][j-a[i]]+1, dp[i+1][j-a[i]+w[i]]), dp[i][j-1]); //, printf("dp[%d][%d]=%d\n", i, j, dp[i][j]);
md = dp[1][mc];
//cout<<dp[1][mc]<<endl;
for (int i=1; i<=m; ++i) if (c[i]<=md) test[c[i]];
queue<ele> q;
plan p; ele t, t2;
q.push(ele(3, 1, 2));
//met[++size].build(0, 0);
while (!q.empty()) {
t=q.front(); q.pop();
//printf("%d %d\n", t.d, size);
if (t.f>mblood) continue;
if (t.f>1 && !mp1[t.f]) met[++size].build(t.d, t.f);
//p.build(t.d, t.out+1);
//if (!mp1[p]) met[++size]=p;
if (t.d<md) {
//printf("%d\n", mp2.size);
#if 1
t2.build(t.d+1, t.f, t.l+1);
if (1ll*t.f*(t.l+1)<=mblood && !mp2[t2]) q.push(t2);
t2.build(t.d+1, t.f*t.l, t.l);
if (1ll*t.f*t.l<=mblood && !mp2[t2]) q.push(t2);
#else
if (1ll*t.f*(t.l+1)<=mblood) q.push(ele(t.d+1, t.f, t.l+1));
if (t.f*t.l<=mblood) q.push(ele(t.d+1, t.f*t.l, t.l));
#endif
}
}
for (int i=1; i<=m; ++i) for (int j=1; j<=size; ++j) if (met[j].f<=c[i] && met[j].f+md-met[j].d>=c[i]) test[c[i]];
//for (int i=1; i<=size; ++i) cout<<met[i].d<<' '<<met[i].f<<endl;
//cout<<size<<endl<<endl;
#if 0
for (int i=1,t; i<=size; ++i)
for (int j=md-met[i].d; j>=0; --j) {
t = met[i].f+j;
if (t) test[t], cout<<t<<endl;
}
if (cnt>=m) {checkout(); return 0;}
#endif
sort(met+1, met+size+1);
for (int i=1,ci,val; i<=m; ++i) {
ci = c[i];
if (test.query(ci)) continue;
plan *l=met+1, *r=met+size;
while (l<=r) {
val = md+l->f-l->d;
//cout<<l-met<<' '<<r-met<<endl;
while (l->f+r->f > ci) --r;
//cout<<(val+r->f-r->d)<<endl;
if (val+r->f-r->d >= ci) {test[ci]; /*cout<<"pos1"<<endl;*/ goto jump1;}
++l;
}
jump1: ;
}
checkout();
return 0;
}
题解 [AHOI2017/HNOI2017]大佬的更多相关文章
- [AHOI2017/HNOI2017]大佬
Description: 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事 ...
- 【题解】HNOI2017大佬
哎……做了几个小时最后还是没能想到怼大佬的合法性到底怎么搞.写暴力爆搜感觉复杂度爆炸就没敢写 bfs / dfs 一类,后来发现在种种的约束条件下(远小于所给的 \(n, m\))复杂度完全是可以承受 ...
- 【LG3723】[AHOI2017/HNOI2017]礼物
[LG3723][AHOI2017/HNOI2017]礼物 题面 洛谷 题解 首先我们将\(c\)看作一个可以为负的整数,那么我们就可以省去讨论在哪个手环加\(c\)的繁琐步骤了 设我们当前已经选好了 ...
- [AH/HNOI2017]大佬
题目描述 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事情非常不开心,于 ...
- [AH2017/HNOI2017]大佬
题目描述 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事情非常不开心,于 ...
- [HNOI2017]大佬
参考题解 \(\text{Solution}\) 我们发现5个行为中2操作与其它操作无关,所以我们采用贪心,尽量让多的时间去攻击大佬. 设 \(f[i][j]\) 表示前 \(i\) 天剩 \(j\) ...
- bzoj4828 [Hnoi2017]大佬
Description 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语.你作为一个OIER,面对这样的事情非常 ...
- [bzoj4828][Ah/Hnoi2017]大佬
来自FallDream的博客,未经允许,请勿转载,谢谢. 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你 ...
- BZOJ4828 AHOI/HNOI2017大佬(动态规划+bfs)
注意到怼大佬的操作至多只能进行两次.我们逐步简化问题. 首先令f[i][j]表示第i天结束后自信值为j时至多有多少天可以进行非防御操作(即恢复自信值之外的操作).这个dp非常显然.由于最终只需要保证存 ...
随机推荐
- C#下通过wbemtest和WMI Code Cretor更加高效的访问WMI
能找到这篇博客的,相信都是有操作WMI需求的了.但是不知道如何快速验证.并集成到C#来操作WMI.我们分为3步: ##第一步:官网(或跟硬件开发WMI的人沟通你需要的接口和参数定义,如果是和硬件开发的 ...
- WPF教程十二:了解自定义控件的基础和自定义无外观控件
这一篇本来想先写风格主题,主题切换.自定义配套的样式.但是最近加班.搬家.新租的房子打扫卫生,我家宝宝6月中旬要出生协调各种的事情,导致了最近精神状态不是很好,又没有看到我比较喜欢的主题风格去模仿的, ...
- FreeRTOS-00-基础知识+任务创建删除
1 说明 本文仅作为学习FreeRTOS的记录文档,作为初学者肯定很多理解不对甚至错误的地方,望网友指正. 1.1 简介 FreeRTOS是一个RTOS(实时操作系统)系统,支持抢占式.合作式和时间片 ...
- Min25 筛与 Powerful Numbers
Min25 筛与 Powerful Numbers Min25 筛 大喊一声 Min25 NB!!! 这是一个非常神奇的东西,用于求更加普遍的积性函数的前缀和. 比如我们要求 \(\sum_{i=1} ...
- session过期跳转到登陆页面并解决跳出iframe问题
首先,先转载如下这篇博主写的关于后台系统使用iframe不能跳出的问题,地址:https://blog.csdn.net/xiaocen99/article/details/38521649 在ifr ...
- [004] .NET 的现状和未来
我们总是能听到一些人说,.NET 不行.学 .NET 没发展前途之类的言论,有的童鞋听多了便也开始怀疑自己选择的 .NET 方向是不是错了. 不得不承认,在 .NET 没有实现跨平台之前,市场行情确实 ...
- 微信小程序云开发-云存储-带图片的商品列表携带id跳转至商品详情
一.商品列表页 1.wxml文件 在view中添加点击事件goToGoodDetail,绑定数据data-id <!-- 添加点击事件goToGoodDetail --> <view ...
- C++模板封装Win32 API 动态调用
起因 花两周通读了一遍<C++ Primer>,积攒的疑惑一扫而光. 前因 利用C++11可变模板,封装调用dll导出函数 本以为已经很好用了,最近抽时间巩固下知识体系,发现自己道行不够! ...
- 小鹤双拼win10一键恢复布局
起因 一直用的小鹤双拼布局,最近重装系统又要重新配置,麻烦 尝试 查找对应注册表设置,找到以下路径包含相应配置 HKEY_CURRENT_USER\Software\Microsoft\InputMe ...
- C#.NET 国密SM3withSM2签名与验签 和JAVA互通
C# 基于.NET FRAMEWORK 4.5 JAVA 基于 JDK1.8 一.要点 1.签名算法:SM3withSM2. 2.签名值byte[] 转字符串时,双方要统一,这里是BASE64. 二. ...