当前位置: 首页 > 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.dtcms.com/a/289571.html

相关文章:

  • 数控调压BUCK电路 —— 基于TPS56637(TI)
  • 乐观锁实现原理笔记
  • Android activity与service通信的三种方法
  • 30天打牢数模基础-K均值聚类
  • (DINO)Emerging Properties in Self-Supervised Vision Transformers论文精读(逐段解析)
  • (苍穹外卖)暑假学习理解P2
  • 从零搭建智能搜索代理:LangGraph + 实时搜索 + PDF导出完整项目实战
  • [C/C++安全编程]_[中级]_[如何安全使用循环语句]
  • k8s:离线部署存在的相关问题
  • 近期工作感想:职业规划篇
  • 【单片机外部中断实验修改动态数码管0-99】2022-5-22
  • Linux文件系统三要素:块划分、分区管理与inode结构解析
  • 本地部署开源离线内容浏览器 Kiwix 并实现外部访问( Windows 版本)
  • 【Java新特性】Java 21 新特性全解析
  • CSS面试题及详细答案140道之(121-140)
  • 快速理解LLM的temperature和top_p参数
  • 设备健康管理实施案例:从技术架构到落地效果的全栈解析
  • MCP实战案例|Trae2.0 一键创建旅行助手并一键部署EdgeOne
  • ARFoundation系列讲解 - 101 VisionPro 真机调试
  • Vue中组件的生命周期
  • 建筑墙壁损伤缺陷分割数据集labelme格式7820张20类别
  • Django ORM系统
  • [学习] Hilbert变换:从数学原理到物理意义的深度解析与仿真实验(完整实验代码)
  • 平安车管家|中国平安车管家入职测评16PF瑞文IQ测评答题攻略及真题题库
  • 嵌入式系统内核镜像相关(十七)
  • AI 的广泛应用是否会削弱人的思考能力和创造力?
  • GaussDB select into和insert into的用法
  • 字符串处理
  • MySQL学习----Explain
  • 关于堆的判断