当前位置: 首页 > 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.lryc.cn/news/593958.html

相关文章:

  • Web-SQL注入数据库类型用户权限架构分层符号干扰利用过程发现思路
  • 向日葵远程命令执行漏洞
  • 《深入C++多态机制:从虚函数表到运行时类型识别》​
  • IDEA中使用Tomcat两种方式
  • C51单片机学习笔记——定时器与中断
  • API接口签名和敏感信息加密使用国密SM方案
  • 上电复位断言的自动化
  • go-redis Pipeline 与事务
  • 《计算机网络》实验报告五 DNS协议分析与测量
  • Dockerfile配置基于 Python 的 Web 应用镜像
  • 随着GPT-5测试中泄露OpenAI 预计将很快发布 揭秘GPT-5冲击波:OpenAI如何颠覆AI战场,碾压谷歌和Claude?
  • 单片机启动流程和启动文件详解
  • 数组算法之【合并两个有序数组】
  • 嵌入式硬件篇---舵机(示波器)
  • 设备健康管理实施案例:从技术架构到落地效果的全栈解析
  • 嵌入式硬件篇---机械臂运动学解算(3自由度)
  • 【MySQL】索引中的页以及索引的分类
  • 全面解析MySQL(2)——CRUD基础
  • RabbitMQ面试精讲 Day 4:Queue属性与消息特性
  • UDP中的单播,多播,广播
  • RabbitMQ核心组件浅析:从Producer到Consumer
  • 30个常用的Linux命令汇总和实战场景示例
  • 使用 Pyecharts 绘制精美饼状图:从基础到高级技巧
  • nginx定期清理日志
  • Node.js:函数、路由、全局对象
  • 数据并表技术全面指南:从基础JOIN到分布式数据融合
  • 分布式文件系统04-DataNode海量数据分布式高可靠存储
  • ZooKeeper学习专栏(一):分布式协调的核心基石
  • 【橘子分布式】gRPC(编程篇-下)
  • C++STL系列之list