当前位置: 首页 > news >正文

AtCoder Beginner Contest 415

AtCoder Beginner Contest 415

A题

枚举xxx是否在序列AAA中即可。

B题

模拟题,将s[i]==′#′s[i]=='\#'s[i]==#的位置保存在ans中,之后每次输出两个即可。

C题

状压dp

定义dp[i]dp[i]dp[i]表示状态iii可达,初始化dp[0]=1dp[0]=1dp[0]=1

转移方程:假设当前状态为iii,且dp[i]==1dp[i]==1dp[i]==1,那么枚举iii的每一位,如果为0,那么我们判断是否能够转移。假设第jjj位为0,那么新的状态state=i+1<<jstate=i+1<<jstate=i+1<<j,如果s[state]==′0′s[state]=='0's[state]==0,那么可以转移过去dp[state]=1dp[state]=1dp[state]=1,最后跑完了之后只需要检查dp[(1<<n)−1]==1?Yes:Nodp[(1<<n)-1]==1?Yes:Nodp[(1<<n)1]==1?Yes:No

void solve(){int n;string s;cin >> n >> s;s=" "+s;if(s.back()=='1'){cout << "No" << endl;return;}vector<int> ok(1LL<<n,0);
//	for(int i=1;i<=n;i++){
//		if(s[1LL<<(i-1)]=='0') ok[1LL<<(i-1)]=1;
//	}ok[0]=1;for(int i=0;i<(1LL<<n);i++){//i就是状态if(ok[i]){//枚举到达这个状态没有使用过的药品for(int j=0;j<n;j++){if(i>>j &1) continue;//如果没有使用,那么可以用来转移int nxt=i+(1<<j);if(s[nxt]=='0') ok[nxt]=1;}}}if(ok[(1LL<<n) -1]) cout << "Yes" << endl;else cout << "No" << endl;
}

D题

贪心

我们每次选能够选择中的亏损最少的那个,因为可以多次选。假设当前有NNN瓶,选第iii个,能够选xxx次,那么在第x−1x-1x1次选完之后,肯定有N−(x−1)×(Ai−Bi)≥AiN-(x-1)\times(A_i-B_i)\geq A_iN(x1)×(AiBi)Ai,那么化简N+Ai−Bi−Ai>=x×(Ai−Bi)N+A_i-B_i-A_i>=x\times(A_i-B_i)N+AiBiAi>=x×(AiBi),得到x≤N−BiAi−Bix\leq \frac{N-B_i}{A_i-B_i}xAiBiNBixxx向下取整。

之后就是先按照差值从小到大排序,依次枚举,统计答案。

struct node{int a,b;bool operator <(node other){if(a-b!=other.a-other.b) return a-b<other.a-other.b;else return a<b;}
};void solve(){int n,m;cin >> n >> m;vector<int> A(m+1),B(m+1);for(int i=1;i<=m;i++){cin >> A[i] >> B[i];}vector<node> vt(m+1);for(int i=1;i<=m;i++){vt[i]={A[i],B[i]};}sort(vt.begin()+1,vt.end());int ans=0;//可以多次和i交换,那么计算出可以交换的次数for(int i=1;i<=m;i++){if(n<vt[i].a) continue;int x=(n-vt[i].b)/(vt[i].a-vt[i].b);ans+=x;n-=x*(vt[i].a-vt[i].b);}cout << ans << endl;
}

E题

二分+dp

定义dp[i][j]dp[i][j]dp[i][j]表示在第i+j−1i+j-1i+j1个监狱买完饭之后能够剩余最多的金币数。

const int maxn=2e5+9,mod=1e9+7;
int p[maxn];
bool check(int mid,vector<vector<int>>&a,int n,int m){vector<vector<int>> dp(n+1,vector<int>(m+1,-inf));//inf特判dp[1][1]=mid+a[1][1]-p[1+1-1];if(dp[1][1]<0) return false;//先转移第一行for(int j=2;j<=m;j++){if(dp[1][j-1]>=0){dp[1][j]=dp[1][j-1]+a[1][j]-p[1+j-1];}}for(int i=2;i<=n;i++){if(dp[i-1][1]>=0){dp[i][1]=dp[i-1][1]+a[i][1]-p[1+i-1];}}for(int i=2;i<=n;i++){for(int j=2;j<=m;j++){if(!(dp[i-1][j]<0&&dp[i][j-1]<0)){dp[i][j]=max(dp[i-1][j],dp[i][j-1])+a[i][j]-p[i+j-1];}}}return dp[n][m]>=0;
}void solve(){int n,m;cin >> n >> m;vector<vector<int>> a(n+1,vector<int>(m+1));for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin >> a[i][j];}}for(int i=1;i<=n+m-1;i++) cin>>p[i];p[n+m]=0;
//	a[n][m]=0;int l=0,r=inf,mid,ans;while(l<=r){mid=(l+r)/2;if(check(mid,a,n,m)){ans=mid;r=mid-1;}else l=mid+1;}cout << ans << endl;
}

F题

线段树区间合并

对于每一个节点,我们要维护这些信息:左端点lll,右端点rrr,包含左端点的前缀最大连续相同字符长度preprepre,包含右端点的最大连续相同字符长度sufsufsuf,节点的最长连续相同字符长度mxmxmx

pushuppushuppushupqueryqueryquery的时候,要手动合并信息即可。

#include<bits/stdc++.h>
using namespace std;
#define inf 1e18
#define endl '\n'
#define int long long
#define lc u<<1
#define rc u<<1|1
typedef  long long ll;
typedef pair<int,int> pii;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
const int maxn=5e5+9,mod=1e9+7;
char s[maxn];
struct segment{int l,r;int pre,suf,mx;
}tr[maxn<<2];
void pushup(int u){tr[u].pre=tr[lc].pre;if(tr[lc].r-tr[lc].l+1==tr[lc].pre&&s[tr[lc].r]==s[tr[rc].l]){tr[u].pre=max(tr[u].pre,tr[lc].r-tr[lc].l+1+tr[rc].pre);}tr[u].suf=tr[rc].suf;if(tr[rc].r-tr[rc].l+1==tr[rc].suf&&s[tr[lc].r]==s[tr[rc].l]){tr[u].suf=max(tr[u].suf,tr[rc].r-tr[rc].l+1+tr[lc].suf);}tr[u].mx=max(tr[lc].mx,tr[rc].mx);if(s[tr[lc].r]==s[tr[rc].l]){tr[u].mx=max(tr[u].mx,tr[lc].suf+tr[rc].pre);}
}void build(int u,int l,int r){tr[u]={l,r,1,1,1};if(l==r) return;int mid=(l+r)/2;build(lc,l,mid);build(rc,mid+1,r);pushup(u);
}
void update(int u,int l,int r,char c){if(tr[u].l==tr[u].r){s[l]=c;//前缀最大长度,后缀最大长度不会改变,因为是单点tr[u].suf=tr[u].pre=tr[u].mx=1;return;}int mid=(tr[u].l+tr[u].r)/2;if(l<=mid) update(lc,l,r,c);if(r>mid) update(rc,l,r,c);pushup(u);
}
segment query(int u,int l,int r){if(tr[u].l>=l&&tr[u].r<=r){return tr[u];}//babaacczccint mid=(tr[u].l+tr[u].r)/2;if(r<=mid) return query(lc,l,r);if(l>mid) return query(rc,l,r);segment left,right,res;left=query(lc,l,r);right=query(rc,l,r);res.l=left.l;res.r=right.r;//区间合并res.pre=left.pre;if(left.pre==left.r-left.l+1&&s[left.r]==s[right.l]){res.pre=max(res.pre,left.r-left.l+1+right.pre);}res.suf=right.suf;if(right.suf==right.r-right.l+1&&s[left.r]==s[right.l]){res.suf=max(res.suf,right.r-right.l+1+left.suf);}res.mx=max(left.mx,right.mx);if(s[left.r]==s[right.l]){res.mx=max(res.mx,left.suf+right.pre);}return res;
}
void solve(){int n,q;cin >> n >> q;for(int i=1;i<=n;i++){cin >> s[i];}build(1,1,n);while(q--){int op,l,r,pos;char c;cin >> op;if(op==1){cin >> pos >> c;update(1,pos,pos,c);}else{cin >> l >> r;segment res=query(1,l,r);cout << res.mx << endl;}}
}
/*
找到区间最长相同字符长度,那么要维护信息区间左右端点以及每个区间以第一个字符开头的最长连续相同字符长度
和最后一个字符向前的最长长度
用于区间合并,其他不用
也就是向上合并信息时,最长长度为左边最长长度,右边最长长度,以及可能中间的
*/
signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);int t=1;
//	cin >> t;while(t--){solve();}return 0;
}
http://www.xdnf.cn/news/1158859.html

相关文章:

  • Linux系统中全名、用户名、主机名的区别
  • Unity学习笔记(五)——3DRPG游戏(2)
  • 《拆解WebRTC:NAT穿透的探测逻辑与中继方案》
  • (苍穹外卖)暑假学习理解P2
  • 平安车管家|中国平安车管家入职测评16PF瑞文IQ测评答题攻略及真题题库
  • UDP中的单播,多播,广播(代码实现)
  • securecrt连接服务器报错 Key exchange failed 怎么办
  • 在服务器无网络的环境下安装 VS Code Remote-SSH 组件
  • Linux-基础知识总结
  • 【算法300题】:双指针
  • 搭建大模型
  • Dockerfile配置基于 Python 的 Web 应用镜像
  • 前端静态资源免费cdn服务推荐
  • 【分布式 ID】详解百度 uid-generator(源码篇)
  • 企业安全防护:堡垒机技术解析
  • WireShark抓包分析TCP数据传输过程与内容详解
  • Linux场景常见的几种安装方式
  • 在C++里如何避免栈内存溢出
  • C++ primer知识点总结
  • 深度学习图像分类数据集—八种贝类海鲜食物分类
  • 基于Chinese-LLaMA-Alpaca-3的多模态中医舌诊辅助诊断系统设计与实现
  • day24——Java高级技术深度解析:单元测试、反射、注解与动态代理
  • 零基础 “入坑” Java--- 十三、再谈类和接口
  • ABP VNext + Playwright E2E:前后端一体化自动化测试
  • 苍穹外卖|项目日记(完工总结)
  • 基于Transformer的智能对话系统:FastAPI后端与Streamlit前端实现
  • 【RK3576】【Android14】ADB工具说明与使用
  • 企业级安全威胁检测与响应(EDR/XDR)架构设计
  • xavier nx上编译fast-livo过程中出现的问题记录
  • C++现代编程之旅:从基础语法到高性能应用开发