20240724模拟赛订正题笔记
(T1)lnsyoj2208 逆流而上/P10737 [SEERC2020] Reverse Game
考虑到失败时字符串应为前面都是0,后面都是1(例如"0000001111111")
所以可以将原串的逆序对数求出,记为m,对于每个可翻转的串进行分类讨论:
1."10"->"01"可以将原串的逆序对减1。
2."100"->"001" "110"->"011" "1010"->"0101"可以将原串的逆序对减2。
综上所述,该问题变成了取石子问题。
所以当m%3==0时后手(B)胜,否则先手(A)胜。
代码如下:
#include <cstdio> #include <cstring> #define int long long using namespace std; int cnt1; int T; int n; char s[1000005]; signed main(){ scanf("%lld",&T); while(T--){ scanf("%s",s+1); n=strlen(s+1); cnt1=0; int res=0; for(int i=1;i<=n;i++){ if(s[i]=='1'){ cnt1++; } else if(s[i]=='0'){ res+=cnt1; } } if(res%3==0){ printf("B\n"); } else{ printf("A\n"); } } return 0; }
(T2)lnsyoj2209 帝国飘摇/P10455 Genius Acm
首先若固定一组零件的左端点,则右端点越靠右越好,所以选择贪心。
对于一组零件内,可以一个指针从大到小选数,另一个指针从小到大选数,这样即可以使val最大。
所以可以倍增枚举右端点,枚举时进行排序,时间复杂度
排序时可以不排整个一组,可以只排新增加进的零件,然后原先一组和新进的零件都是有序的,所以可以
代码如下:
#include <cstdio> #include <algorithm> #define int long long using namespace std; int T; int n,m,k; struct vi{ int data; }vis[500005],gbvis[500005],yvis[500005]; bool cmp1(vi a,vi b){ return a.data<b.data; } signed main(){ scanf("%lld",&T); while(T--){ scanf("%lld%lld%lld",&n,&m,&k); for(int i=1;i<=n;i++){ scanf("%lld",&yvis[i].data); } int lr=0; int ans=0; for(int l=1,r=0,base=0;l<=n;base++){ if(base==-1){ l=r+1; base=0; ans++; } lr=r; r+=1<<base; if(r>n){ base-=2; r=lr; } for(int i=lr+1;i<=r;i++){ vis[i].data=yvis[i].data; } sort(vis+lr+1,vis+r+1,cmp1); if(l<=lr){ int i1=l,j1=lr+1,k1=l; while(i1<=lr && j1<=r){ if(vis[i1].data<vis[j1].data){ gbvis[k1].data=vis[i1].data; k1++; i1++; } else{ gbvis[k1].data=vis[j1].data; k1++; j1++; } } while(i1<=lr){ gbvis[k1].data=vis[i1].data; k1++; i1++; } while(j1<=r){ gbvis[k1].data=vis[j1].data; k1++; j1++; } } else{ for(int i=l;i<=r;i++){ gbvis[i].data=vis[i].data; } } int x=r-l+1; int val=0; if(x<2*m){ for(int i=1;i<=x/2;i++){ val+=(gbvis[l+i-1].data-gbvis[r-i+1].data)*(gbvis[l+i-1].data-gbvis[r-i+1].data); } } else{ for(int i=1;i<=m;i++){ val+=(gbvis[l+i-1].data-gbvis[r-i+1].data)*(gbvis[l+i-1].data-gbvis[r-i+1].data); } } if(val>k){ base-=2; r=lr; } else{ for(int i=l;i<=r;i++){ vis[i].data=gbvis[i].data; } } } printf("%lld\n",ans); } return 0; }
(T3)lnsyoj2210 致命冲击/P5069 [Ynoi2015] 纵使日薄西山
此题我们可以利用线段树维护此序列的权值,具体如下:
在一个操作中,若选择了一个数,则这个数两边的数不能被选。(证明:因为若选择此数,则必须满足此数大于这个数两边的数,通过不等式的性质得知这个数两边的数在之后的操作中也不能被选)
可已将此序列拆成若干序列,通过上个结论可以使线段树具有可合并性,所以对这些数列进行合并,合并过程充分利用了pushup。
两个序列合并一共分为两种情况:
1.左序列最右的数被选 且 右序列最左的数被选:
此时选两个数中最大的数,另一个数强制不被选。
2.左序列最右的数没被选 或 右序列最左的数没被选 或 两个数都没被选:
此时直接合并即可。
所以线段树需要维护:(左端点:序列最左的元素 右端点:左端点:序列最右的元素)
1.当序列左右端点都可以被选时序列的权值
2.当序列左端点强制不被选 且 右端点可以被选 时序列的权值
3.当序列右端点强制不被选 且 左端点可以被选 时序列的权值
4.当序列左端点强制不被选 且 右端点强制不被选 时序列的权值
5.当序列左右端点都可以被选时序列左端点是否被选中
6.当序列左端点强制不被选 且 右端点可以被选 时序列左端点是否被选中
7.当序列右端点强制不被选 且 左端点可以被选 时序列左端点是否被选中
8.当序列左端点强制不被选 且 右端点强制不被选 时序列左端点是否被选中
9.当序列左右端点都可以被选时序列右端点是否被选中
10.当序列左端点强制不被选 且 右端点可以被选 时序列右端点是否被选中
11.当序列右端点强制不被选 且 左端点可以被选 时序列右端点是否被选中
12.当序列左端点强制不被选 且 右端点强制不被选 时序列右端点是否被选中
13.序列左端点的大小
14.序列右端点的大小
pushup函数需要对以上所有进行维护
代码如下:
#include <cstdio> #define int long long using namespace std; struct node{ int data[4];//0:YY 1:YN 2:NY 3:NN bool xl[4]; bool xr[4]; int shul; int shur; }ns[400005]; int n,q,a[100005]; inline void pushup(int id){ if(ns[id*2].xr[0] && ns[id*2+1].xl[0]){ if(ns[id*2].shur>=ns[id*2+1].shul){ ns[id].xl[0]=ns[id*2].xl[0]; ns[id].xr[0]=ns[id*2+1].xr[2]; ns[id].data[0]=ns[id*2].data[0]+ns[id*2+1].data[2]; } else{ ns[id].xl[0]=ns[id*2].xl[1]; ns[id].xr[0]=ns[id*2+1].xr[0]; ns[id].data[0]=ns[id*2].data[1]+ns[id*2+1].data[0]; } } else{ ns[id].xl[0]=ns[id*2].xl[0]; ns[id].xr[0]=ns[id*2+1].xr[0]; ns[id].data[0]=ns[id*2].data[0]+ns[id*2+1].data[0]; } if(ns[id*2].xr[0] && ns[id*2+1].xl[1]){ if(ns[id*2].shur>=ns[id*2+1].shul){ ns[id].xl[1]=ns[id*2].xl[0]; ns[id].xr[1]=ns[id*2+1].xr[3]; ns[id].data[1]=ns[id*2].data[0]+ns[id*2+1].data[3]; } else{ ns[id].xl[1]=ns[id*2].xl[1]; ns[id].xr[1]=ns[id*2+1].xr[1]; ns[id].data[1]=ns[id*2].data[1]+ns[id*2+1].data[1]; } } else{ ns[id].xl[1]=ns[id*2].xl[0]; ns[id].xr[1]=ns[id*2+1].xr[1]; ns[id].data[1]=ns[id*2].data[0]+ns[id*2+1].data[1]; } if(ns[id*2].xr[2] && ns[id*2+1].xl[0]){ if(ns[id*2].shur>=ns[id*2+1].shul){ ns[id].xl[2]=ns[id*2].xl[2]; ns[id].xr[2]=ns[id*2+1].xr[2]; ns[id].data[2]=ns[id*2].data[2]+ns[id*2+1].data[2]; } else{ ns[id].xl[2]=ns[id*2].xl[3]; ns[id].xr[2]=ns[id*2+1].xr[0]; ns[id].data[2]=ns[id*2].data[3]+ns[id*2+1].data[0]; } } else{ ns[id].xl[2]=ns[id*2].xl[2]; ns[id].xr[2]=ns[id*2+1].xr[0]; ns[id].data[2]=ns[id*2].data[2]+ns[id*2+1].data[0]; } if(ns[id*2].xr[2] && ns[id*2+1].xl[1]){ if(ns[id*2].shur>=ns[id*2+1].shul){ ns[id].xl[3]=ns[id*2].xl[2]; ns[id].xr[3]=ns[id*2+1].xr[3]; ns[id].data[3]=ns[id*2].data[2]+ns[id*2+1].data[3]; } else{ ns[id].xl[3]=ns[id*2].xl[3]; ns[id].xr[3]=ns[id*2+1].xr[1]; ns[id].data[3]=ns[id*2].data[3]+ns[id*2+1].data[1]; } } else{ ns[id].xl[3]=ns[id*2].xl[2]; ns[id].xr[3]=ns[id*2+1].xr[1]; ns[id].data[3]=ns[id*2].data[2]+ns[id*2+1].data[1]; } ns[id].shul=ns[id*2].shul; ns[id].shur=ns[id*2+1].shur; } void build(int id,int l,int r){ if(l==r){ ns[id].data[0]=a[l]; ns[id].xl[0]=ns[id].xr[0]=true; ns[id].shul=a[l]; ns[id].shur=a[l]; return; } int mid=(l+r)/2; build(id*2,l,mid); build(id*2+1,mid+1,r); pushup(id); } void set(int id,int l,int r,int wei,int zhi){ if(l==r){ ns[id].data[0]=zhi; ns[id].shul=zhi; ns[id].shur=zhi; return; } int mid=(l+r)/2; if(wei<=mid){ set(id*2,l,mid,wei,zhi); } else{ set(id*2+1,mid+1,r,wei,zhi); } pushup(id); } signed main(){ scanf("%lld%lld",&n,&q); for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } build(1,1,n); while(q--){ int x,y; scanf("%lld%lld",&x,&y); set(1,1,n,x,y); printf("%lld\n",ns[1].data[0]); } return 0; }
(T4)lnsyoj2211 通天之塔/P10652 「ROI 2017 Day 1」前往大都会
此题一共有两个问,可以分别求一下:
1.对于第一问,直接跑最短路即可。
2.对于第二问,可以使用dp解决,方法如下:
设
可得
利用斜率优化dp,经过化简得
由此得
因为要使
考虑
对于本题需要先建一个最短路图(
对于所有点需要按
最后得出答案。
(实际不用新建图,只需要记录一下每个点被哪条铁路线所经过即可)
代码如下:
#include <iostream> #include <vector> #include <queue> #include <cstring> #include <algorithm> #define int long long using namespace std; struct Edge{ int next; int to; int w; //int vi; int u; }es[2000005]; int head[1000005],cnt; vector<int> vi[1000005]; vector<int> nr[1000005]; inline void add(int u,int v,int w,int vi1){ es[cnt].next=head[u]; es[cnt].to=v; es[cnt].w=w; es[cnt].u=u; vi[vi1].push_back(cnt); head[u]=cnt; cnt++; } int n,m; priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > pq; struct ys{ int dis; int id; }yss[1000005]; bool cmp1(ys a,ys b){ return a.dis<b.dis; } bool cmp2(ys a,ys b){ return a.id<b.id; } bool vis[1000005]; int dp[1000005]; vector<int> stas[1000005]; vector<int> cov[1000005]; inline int calc(int i,int j){//yss编号 return dp[yss[j].id]+(yss[i].dis-yss[j].dis)*(yss[i].dis-yss[j].dis); } inline long double slope(int a,int b){//yss编号 return 1.0*(dp[yss[a].id]+yss[a].dis*yss[a].dis-dp[yss[b].id]-yss[b].dis*yss[b].dis)/\ (long double)(yss[a].dis-yss[b].dis); } int cntv; signed main(){ cnt=1; scanf("%lld%lld",&n,&m); for(int i=1;i<=m;i++){ int l,u,v,w; scanf("%lld",&l); scanf("%lld",&u); for(int j=1;j<=l;j++){ scanf("%lld",&w); scanf("%lld",&v); add(u,v,w,i); u=v; } } for(int i=1;i<=n;i++){ yss[i].dis=0x3f3f3f3f3f3f3f3f; yss[i].id=i; } yss[1].dis=0; pq.push({0,1}); while(!pq.empty()){ int u=pq.top().second; pq.pop(); if(vis[u]){ continue; } vis[u]=true; for(int i=head[u];i;i=es[i].next){ int v=es[i].to; if(yss[u].dis+es[i].w<yss[v].dis){ yss[v].dis=yss[u].dis+es[i].w; pq.push({yss[v].dis,v}); } } } for(int i=1;i<=m;i++){ for(int j=0;j<vi[i].size();j++){ if(yss[es[vi[i][j]].u].dis+es[vi[i][j]].w==yss[es[vi[i][j]].to].dis){ nr[i].push_back(vi[i][j]); } } } for(int i=1;i<=m;i++){ if(!nr[i].empty()){ cntv++; cov[es[nr[i][0]].u].push_back(cntv); cov[es[nr[i][0]].to].push_back(cntv); } for(int j=1;j<nr[i].size();j++){ if(es[nr[i][j]].u!=es[nr[i][j-1]].to){ cntv++; cov[es[nr[i][j]].u].push_back(cntv); } cov[es[nr[i][j]].to].push_back(cntv); } } sort(yss+1,yss+n+1,cmp1); for(int i=1;i<=n;i++){ for(int j=0;j<cov[yss[i].id].size();j++){ if(stas[cov[yss[i].id][j]].empty()){ continue; } while(stas[cov[yss[i].id][j]].size()>1 && \ calc(i,stas[cov[yss[i].id][j]][stas[cov[yss[i].id][j]].size()-1])<\ calc(i,stas[cov[yss[i].id][j]][stas[cov[yss[i].id][j]].size()-2])){ stas[cov[yss[i].id][j]].pop_back(); } dp[yss[i].id]=max(dp[yss[i].id],calc(i,stas[cov[yss[i].id][j]].back())); } for(int j=0;j<cov[yss[i].id].size();j++){ while(stas[cov[yss[i].id][j]].size()>1 && \ slope(i,stas[cov[yss[i].id][j]][stas[cov[yss[i].id][j]].size()-1])>\ slope(stas[cov[yss[i].id][j]][stas[cov[yss[i].id][j]].size()-1],stas[cov[yss[i].id][j]][stas[cov[yss[i].id][j]].size()-2])){ stas[cov[yss[i].id][j]].pop_back(); } stas[cov[yss[i].id][j]].push_back(i); } } sort(yss+1,yss+n+1,cmp2); printf("%lld %lld\n",yss[n].dis,dp[n]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】