2022“杭电杯”中国大学生算法设计超级联赛(3)1002/1011补题

2022“杭电杯”中国大学生算法设计超级联赛(3)

大量参考官方题解

1002 Boss Rush

题意:给定n个技能,每个技能最多使用一次,释放第i个技能需要的回合数为ti,伤害持续的回合为leni,持续回合的伤害为di,j(1jleni)。在一个技能释放时不能释放其他技能,问伤害达到H需要的回合数至少为多少。(1n18,1H1018,1ti,leni105,1di,j109)

思路:发现H很大,考虑二分答案 。二分答案需要求出给定的回合内能造成的最大伤害,暴力算的复杂度是阶乘,肯定T。但是发现n很小,可以二进制枚举已经释放过的技能,设这个集合为S,定义FS为当前集合在给定回合内能够造成的最大伤害,枚举不在当前集合的技能x作为下一个技能进行状态转移

状态转移:

xwFS+x=max(FS+x,FS+w)

AC代码:

时间复杂度 O(n2nlogans)

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
typedef long long LL;
const int N = 20, M = 1e5 + 10;
int n,dd[20];
LL H,f[1<<N];
struct WEAPON{
int k,m;
LL dmg[M];
}wp[N];
void init(){
dd[0]=1;
rep(i,1,20) dd[i]=dd[i-1]<<1;
}
bool check(int rd){
rep(i,0,(1<<n)-1) f[i]=-1;
f[0]=0;
for(int j=0;j < 1<<n;j++){
if(f[j]==-1) continue;
LL cur_w=0;
rep(k,0,n-1) if(j>>k&1) cur_w+=wp[k].k;
rep(k,0,n-1){
if(j>>k&1) continue;
if(rd-cur_w>0){
int t=rd-cur_w;
f[j+dd[k]]=max(f[j+dd[k]],f[j]+wp[k].dmg[min(wp[k].m,t)]);
if(f[j+dd[k]]>=H) return true;
}
}
}
return false;
}
void work() {
cin>>n>>H;
int sum=0;
rep(i,0,n-1)
rep(j,0,M-1) wp[i].dmg[j]=0;
rep(i,0,n-1){
cin>>wp[i].k>>wp[i].m;
sum+=max(wp[i].k,wp[i].m);
rep(j,1,wp[i].m){
LL t;
cin>>t;
wp[i].dmg[j]=wp[i].dmg[j-1]+t;
}
}
int l=1,r=sum+1;
while(l<r){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<(l==sum+1?-1:l-1)<<endl;
}
signed main() {
IO
init();
int test=1;
cin >> test;
while (test--)
work();
return 0;
}

1011 Taxi

题意:给定n个点,第i个点的坐标为(xi,yi) ,权值为 wi,有q个询问,每个询问给定一个点,坐标为(x,y),求min(|xxi|+|yyi|,wi)(1in)

思路:如果没有wi的限制,那么是经典问题。根据|x|=max(x,x),有

max{|xxi|+|yyi|}=max{max(xxi,x+xi)+max(yyi,y+yi)}=max{xxi+yyi,x+xi+yyi,xxiy+yi,x+xiy+yi}=max{(x+y)+(xiyi),(xy)+(xi+yi),(x+y)+xiyi),(xy)+(xi+yi)}

可以发现只要分别记录xi+yi,xiyi,xi+yi,xiyi的最大值就可以在O(1)时间内求出所有点到(x,y)的曼哈顿距离的最大值。

接下来的步骤是把n个点以wi从小到大排序,维护上述四个值的后缀最大值然后二分区间,推荐看官方题解十分详细

AC代码:

时间复杂度O((n+q)logn)

#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N = 1e5 + 10;
struct Point{
int X,Y,W;
}p[N];
int a[N],b[N],c[N],d[N];
bool cmp(Point &x,Point &y){
return x.W<y.W;
}
void work() {
int n,q;
cin>>n>>q;
rep(i,1,n) cin>>p[i].X>>p[i].Y>>p[i].W;
sort(p+1,p+n+1,cmp);
a[n+1]=-INF,b[n+1]=-INF,c[n+1]=-INF,d[n+1]=-INF;
rrep(i,n,1){
a[i]=max(p[i].X+p[i].Y,a[i+1]);
b[i]=max(p[i].X-p[i].Y,b[i+1]);
c[i]=max(-p[i].X+p[i].Y,c[i+1]);
d[i]=max(-p[i].X-p[i].Y,d[i+1]);
}
while(q--){
int x,y;
cin>>x>>y;
int l=1,r=n,ans=0;
while(l<=r){
int mid=l+r>>1;
int cur_w=p[mid].W;
int cur_d=-x-y+a[mid];
cur_d=max(cur_d,-x+y+b[mid]);
cur_d=max(cur_d,x-y+c[mid]);
cur_d=max(cur_d,x+y+d[mid]);
if(cur_w<=cur_d){
ans=max(ans,cur_w);
l=mid+1;
}
else{
ans=max(ans,cur_d);
r=mid-1;
}
}
cout<<ans<<endl;
}
}
signed main() {
IO
int test=1;
cin >> test;
while (test--)
work();
return 0;
}

能力有限欢迎勘误

本文作者:xhy666

本文链接:https://www.cnblogs.com/xhy666/p/16523221.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xhy666  阅读(146)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起