THUSC2013
魔塔
BZOJ
设每个敌人的属性值为\(hp_i,atk_i,def_i\)。自己的为\(HP,ATK,DEF\)
首先我们可以发现顺序是没有影响的。
然后我们可以发现合适的\(ATK\)一定满足\(\max(hp_i+def_i)\ge ATK>\max(def)\),\(DEF\)一定满足\(DEF\le\max(atk_i)\)。
对于一个确定的\(ATK,DEF\),我们可以计算出\(HP=\sum(\lceil\frac{hp_i}{ATK-def_i}\rceil\max(0,atk_i-DEF))+1\)。
也就是说总费用是一个关于\(ATK,DEF\)的二元函数。
看到\(\lceil\frac{hp_i}{ATK-def_i}\rceil\)我们会马上想到除法分块,这东西最多有\(\sqrt{hp_i}\)个取值。因为所有的属性值都是\(1e6\)级别的,所以总的取值个数是\(n\sqrt{1e6}\)级别的。当然我们的\(ATK\)最大只能取到\(2e6\)。
所以我们考虑,假如我们固定了一个\(ATK\),设\(f(x)\)表示此时\(DEF\ from\ x-1\ to\ x\)的\(-\Delta HP\)。\(f(x)\)显然是一个分段函数。
如果你对“\(ATK-DEF\)”这类的计算公式有一定了解的话,可以直接得出下面两个结论:
\(1.f(x)\)严格单调不增。
\(2.\)随着\(ATK\)的增加,\(f(x)\)严格单调不增。
一句话理解就是\(ATK,DEF\)都具有边界效应。
详细点讲的话,
\(1.\)当\(DEF\)增大时,\(\max(0,atk_i-DEF)\)会有越来越多的取到\(0\),也就是\(HP\)递减的速度越来越慢,即\(f(x)\)严格单调不增。
\(2.\)随着\(ATK\)递增,\(\lceil\frac{hp_i}{ATK-def_i}\rceil\)递减,也就是\(HP\)递减的速度越来越慢,即\(f(x)\)严格单调不增。
根据第一条性质,我们可以在固定一个\(ATK\)时,通过二分找到第一个\(f(x)<Cost_{DEF}\)的位置,从而找到最优的\(DEF\)。
根据第二条性质,当\(ATK\)增大时,第一个\(f(x)<Cost_{DEF}\)的位置一定只会向左移,我们可以维护一个单调指针来找到最优的\(DEF\)。
然后讲下如何具体维护\(f(x)\)。
当\(ATK\ from\ x-1\ to\ x\),会有部分\(\lceil\frac{hp_i}{ATK-def_i}\rceil\)发生\(-1\)的变化从而导致\(f(x)\)变化。
观察可以发现这个变化相当于对\(f(x)\)的一段前缀减一个数。并且根据上文除法分块部分的分析总的变化次数大概是\(1e7\)级别的。
因为最优\(DEF\)是单调左移的,所以我们可以直接把前缀减反映到差分数组上(即减的最后一位),在\(DEF\)指针左移时直接计算影响,如果这个前缀超过了\(DEF\),那么超过\(DEF\)的部分是没有影响的。
然后这题卡空间,需要用链表/前向星。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read(){int x;scanf("%d",&x);return x;}
const int N=2000007;
int n,ca,cd,mx,ATK,DEF,head[N],ver[N*5],Next[N*5],edge[N*5],tot;ll a[N],ans,sum,HP,X,Y,Z;
void add(int x,int y,int id){ver[++tot]=x,Next[tot]=head[id],edge[tot]=y,head[id]=tot;}
void update(int p,int v){a[p]+=v;if(Y<=p)sum+=v,Z+=(p-Y)*v;}
int main()
{
n=read(),ca=read(),cd=read(),ans=1e18,Y=1e6,Z=1;
for(int i=1,l,hp,atk,def;i<=n;++i)
{
hp=read()-1,atk=read(),def=read();
for(l=1;l<=hp;l=(hp/(hp/l))+1) if(l==1) add(atk,hp+1,def+1); else add(atk,hp/l-hp/(l-1),def+l);
add(atk,-1,hp+def+1),mx=max(mx,def);
}
for(X=1;X<=2e6;++X)
{
for(int i=head[X];i;i=Next[i]) update(ver[i],edge[i]);
if(X<=mx) continue;
while(Y>1&&sum<cd) Z+=sum,sum+=a[--Y];
if(Z+X*ca+Y*cd<=ans) ans=Z+X*ca+Y*cd,ATK=X,DEF=Y,HP=Z;
}
printf("%lld %d %d",HP,ATK,DEF);
}
宇宙飞艇
BZOJ
第一问随便做,把所有在这个方向的分速度为正的向量全部加上就行了。
第二问可以根据这个扩展一个写法。
随便钦定一个单位向量,把题目给的向量按在这个方向上的分量降序排序。
考虑我们旋转这个单位向量,这个次序会随之变化对吧,也就是有\(n\choose2\)个分界点,经过这个分界点时有两个向量的次序会交换。
假如有多个连续的向量同时交换,那么我们应该reverse而不是一个个swap。(可以自己画图模拟)
可以发现最优的答案一定会在分界点取到。
那么我们顺时针枚举一遍,维护次序数组,每次取在这个方向上分量为正的就行了,最后去最大值。
假如强制选\(k\)个,那就取当前次序前\(k\)个就行了。
#include<bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
int read(){int x;scanf("%d",&x);return x;}
ll max(ll a,ll b){return a>b? a:b;}
const int N=1007;
int n,m,id[N],pos[N],bd[N];vector<int>in;
struct vec{ll x,y;ld arg;vec(int a=0,int b=0):x(a),y(b),arg(atan2(b,a)){}}a[N],ans[N],sum[N],q;
ll len(vec&a){return a.x*a.x+a.y*a.y;}
vec operator+(vec&a,vec&b){return vec(a.x+b.x,a.y+b.y);}
ll operator*(vec&a,vec&b){return a.x*b.x+a.y*b.y;}
int operator==(vec&a,vec&b){return a.x*b.y==a.y*b.x;}
struct line{int a,b;vec x;}b[N*N];
void max(vec&a,vec&b){if(len(b)>len(a))a=b;}
int main()
{
n=read(),q.x=read(),q.y=read();ll tmp=0;
for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read(),tmp+=max(0ll,a[i]*q),id[i]=i;
printf("%lld\n",tmp);
for(int i=1,j;i<=n;++i) for(j=i+1;j<=n;++j) b[++m]={i,j,vec(a[i].y-a[j].y,a[j].x-a[i].x)},b[++m]={i,j,vec(a[j].y-a[i].y,a[i].x-a[j].x)};
sort(b+1,b+m+1,[&](const line&a,const line&b){return a.x.arg<b.x.arg;});
sort(id+1,id+n+1,[](int i,int j){return a[i].x<a[j].x||(a[i].x==a[j].x&&a[i].y<a[j].y);});
for(int i=1;i<=n;++i) ans[i]=sum[i]=sum[i-1]+a[id[pos[id[i]]=i]];
for(int l=1,r,x,y,i;l<=m;l=r)
{
r=l,in.clear();
for(;r<=m&&b[r].x==b[l].x;++r)
{
x=pos[b[r].a],y=pos[b[r].b];
if(x>y) swap(x,y);
if(!bd[x]) in.push_back(x);
bd[x]=max(bd[x],y);
}
sort(in.begin(),in.end());
for(int x:in)
{
if(!bd[x]) continue;
reverse(id+x,id+(y=bd[x])+1);
for(i=x;i<=y;++i) pos[id[i]]=i,bd[i]=0,max(ans[i],sum[i]=sum[i-1]+a[id[i]]);
}
}
tmp=0;
for(int i=1;i<=n;++i) tmp=max(tmp,len(ans[i]));
printf("%lld\n",tmp);
for(int i=1;i<=n;++i) printf("%lld ",len(ans[i]));
}
THUSC2013的更多相关文章
- BZOJ4141 THUSC2013 魔塔 贪心
没得传送门 考虑当\(Atk\)增大时,\(Def\)一定越来越没用,因为回合数在变少.所以考虑从小到大枚举\(Atk\)然后双指针计算. 设\(f_i(x)\)表示在\(Atk = i\)时,\(D ...
随机推荐
- 数据结构实验之数组一:矩阵转置(SDUT 2130)
Problem Description 数组--矩阵的转置 给定一个m*n的矩阵(m,n<=100),求该矩阵的转置矩阵并输出. Input 输入包含多组测试数据,每组测试数据格式如下: 第一行 ...
- hive的两种使用方式
hive的两种使用方式 1,hive shell的方式 启动命令: bin/hive 2.beeline客户端方式 首先在一个机器上启动hive thrift服务 bin/hiveserver2 在其 ...
- Django基础之中间件的执行流程
当请求到达中间件以后,先按照正序执行每个注册中间件的process_request方法,process_request方法返回的值是None,就依次执行. 如果返回的值是HttpResponse对象, ...
- ftp、sftp、vsftp、vsftpd、lftp以及一些网络客户端工具命令
ftp 是File Transfer Protocol的缩写,文件传输协议,用于在网络上进行文件传输的一套标准协议,使用客户/服务器模式.它属于网络传输协议的应用层.了解更多ftp lftp :是一个 ...
- elasticsearch shield在java中的应用
官方文档:https://www.elastic.co/guide/en/shield/current/_using_elasticsearch_java_clients_with_shield.ht ...
- Kafka - SASL认证
kafka SASL认证配置 1.找到kafka安装根目录,在config文件夹下创建kafka_server_jaas.conf,写入 KafkaServer { org.apache.kafka. ...
- oracle 常用工具类及函数
j_param json; jl_keys json_list; -- 创建json对象j_param j_param := json(p_in_str); -- 校验param域是否缺少必填参数 j ...
- Ubuntu JDK环境变量
环境变量配置 sudo gedit ~/.bashrc export JAVA_HOME=/usr/local/java/jdk1.8.0_201 export JRE_HOME=${JAVA_HOM ...
- python 数字转字符保留几位小数 by gisoracle
#数字转字符保留几位小数 by gisoracle #数字转字符保留几位小数 by gisoracle def floattostr(num,xsnum): if xsnum==0: return s ...
- mongoose 实现 增、删、改、查
mongoose常用的API 增 save是一个实例方法,使用时需要先 new Model() 来实例化 //保存一个用户信息,userobj为你创建的文档对象模型里的字段,需正确对应传入 const ...