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

GJOI 10.17/10.18 题解

1.AT_arc119_c ARC Wrecker 2

题意

在这里插入图片描述
多组测试数据 1≤T≤101\le T\le 101T101≤n≤1051\le n\le 10^51n105ai∈[0,109]a_i\in[0,10^9]ai[0,109]

思路

首先容易解决减出负数的情况,直接加一个大数即可。其次对于 a1∼4a_{1\sim 4}a14,先做第一步:
0 a2−a1 a3−a4 00\ a_2-a_1\ a_3-a_4\ 00 a2a1 a3a4 0

此时需要 a2−a1=a3−a4a_2-a_1=a_3-a_4a2a1=a3a4,才能删完。这个条件等价于 a2+a4=a1+a3a_2+a_4=a_1+a_3a2+a4=a1+a3

对于 a1∼5a_{1\sim 5}a15 同样如此:

0 a2−a1 a3 a4−a5 00 0 a3−a2+a1 a4−a5 0\begin{matrix} 0\ a_2-a_1\ a_3\ a_4-a_5\ 0 \\ 0\ 0\ a_3-a_2+a_1\ a_4-a_5\ 0 \end{matrix}0 a2a1 a3 a4a5 00 0 a3a2+a1 a4a5 0

此时需要 a3−a2+a1=a4−a5a_3-a_2+a_1=a_4-a_5a3a2+a1=a4a5 才能删完。这个条件等价于 a5+a3+a1=a2+a4a_5+a_3+a_1=a_2+a_4a5+a3+a1=a2+a4

不难发现一个性质——交错和相等(这和差分有什么关系)。维护奇数位和或者偶数位和,转化为前缀偶数位减去奇数位之和 bib_ibi,转化为子段和为 000 的子段个数,桶维护即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+9;
ll id,Q,n,a[N];
ll s[N],ss[2][N],b[N];
unordered_map<ll,ll>cnt;
int main()
{freopen("edit.in","r",stdin);freopen("edit.out","w",stdout);scanf("%lld%lld",&id,&Q);while(Q--){cnt.clear();cnt[0]=1;scanf("%lld",&n);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);s[i]=s[i-1]+a[i];}ss[1][1]=a[1];ss[1][2]=a[1];for(int i=3;i<=n;i+=2){ss[1][i+1]=ss[1][i]=ss[1][i-2]+a[i];}ss[0][1]=0;for(int i=2;i<=n;i+=2){ss[0][i+1]=ss[0][i]=ss[0][i-2]+a[i];}for(int i=1;i<=n;i++){b[i]=s[i]-2*ss[1][i];}ll ans=0;for(int i=1;i<=n;i++){ans+=cnt[b[i]];cnt[b[i]]++;}printf("%lld\n",ans);}return 0;
}

2.P10100 ROIR2023 石头

题意

在这里插入图片描述
1≤n,q≤1051\le n,q\le 10^51n,q105

思路

注意这是个排列。

先发现几个结论:

  • 一个起始点 x0x_0x0 扩展 k−1k-1k1 次(选数算一次)才能到 ppp,于是 x0∈[p−k+1,p]x_0\in[p-k+1,p]x0[pk+1,p][p,p+k−1][p,p+k-1][p,p+k1]
  • 在左右两端区间,合法 x0x_0x0 的分布,必然是连续的。不难想象,这些合法的 x0x_0x0 都是扩展到统一区间,然后用同样步骤扩展到 ppp

先看 x0∈[p−k+1,p]x_0\in[p-k+1,p]x0[pk+1,p],之所以可以扩展到右边的 ppp 而不去左边的 p−kp-kpk,是因为 ap−k>apa_{p-k}>a_papk>ap。也即 p−k∼x0−1p-k\sim x_0-1pkx01 有个最大值 LmxLmxLmx 大于 x0+1∼px_0+1\sim px0+1p 的最大值。LmxLmxLmx 使得整个扩展过程不会去到太右边,否则会出现 x0x_0x0 右边有个最大值 >ap−k>a_{p-k}>apk,然后被迫扩展到 ap−ka_{p-k}apk 的情况。

因为区间越长最大值单调不降,区间越短最大值单调不增,两边都有单调性,可以二分答案。恰好 kkk 步其实不好做,但是可以转化为至多 kkk 步,这样合法 x0x_0x0 的分布就是从 ppp 向前连续的。

用至多 kkk 步减去至多 k−1k-1k1 步即为答案。区间最大值可以预处理 ST 表。时间复杂度 O(nlog⁡n)O(n\log n)O(nlogn)

注意边界条件的处理。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=1e5+9,M=19,inf=3e14;
ll id,n,Q;
ll a[N];
ll lg2[N],fmx[N][M];
void init()
{lg2[1]=0;lg2[2]=1;for(int i=3;i<N;i++)lg2[i]=lg2[i/2]+1;
}
void getST()
{for(int i=1;i<=n;i++)fmx[i][0]=a[i];for(int j=1;j<=lg2[n];j++)for(int i=1;i+(1<<j)-1<=n;i++)fmx[i][j]=max(fmx[i][j-1],fmx[i+(1<<(j-1))][j-1]);
}
ll query_ma(ll l,ll r)
{if(l<1||r>n||l>r)return inf;//边界无穷大,从而无法向外面扩展ll s=lg2[r-l+1];return max(fmx[l][s],fmx[r-(1<<s)+1][s]);
}
ll sol(ll p,ll k)
{if(k<=1)return k;ll l1=max(1ll,p-k+1),r1=p-1,l2=p+1,r2=min(n,p+k-1);ll ans1=p,ans2=p;ll L1=p-k,R2=p+k;while(l1<=r1){ll mid=(l1+r1)>>1;if(query_ma(mid+1,p)<=query_ma(L1,mid-1))ans1=mid,r1=mid-1;else l1=mid+1; }while(l2<=r2){ll mid=(l2+r2)>>1;if(query_ma(p,mid-1)<=query_ma(mid+1,R2))ans2=mid,l2=mid+1;else r2=mid-1;}return ans2-ans1+1;//ans2-p+1 + p-ans1+1 -1
}
int main()
{freopen("rock.in","r",stdin);freopen("rock.out","w",stdout);scanf("%lld%lld%lld",&id,&n,&Q);init();for(int i=1;i<=n;i++)scanf("%lld",&a[i]);a[0]=a[n+1]=inf;getST();while(Q--){ll p,k;scanf("%lld%lld",&p,&k);ll ansk=sol(p,k),ansk1=sol(p,k-1);printf("%lld\n",ansk-ansk1);}return 0;
}

3.CF1781F Bracket Insertion

4.P10880 JRKSJR9 莫队的 1.5 近似构造

接下来是 GJOI 10.18。

1.洛谷 P5329 SNOI2019 字符串

题意

在这里插入图片描述
多组测试数据 1≤T≤31\le T\le 31T31≤n≤5×1041\le n\le 5\times 10^41n5×104

思路

从前往后扫,如果删去一位,字典序比当前小,那么后面怎么删字典序都没有当前小。所以输出该位。

这些位之外的所有位,删去都会使字典序变大,那么考虑让字典序变化的影响尽量小:即倒着扫回去,把没输出的位输出即可。因为前面的位删了会使字典序变得更大。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=5e5+9;
ll id,Q,n;
char s[N];
ll bel[N],cnt,g[N],tail[N];
bool vis[N];
int main()
{freopen("sort.in","r",stdin);freopen("sort.out","w",stdout);scanf("%lld%lld",&id,&Q);while(Q--){scanf("%lld%s",&n,s+1);ll tot=1;cnt=0;for(int i=1;i<=n;i++){if(s[i]==s[i+1])tot++;else {cnt++;ll num=s[i]-'a'+1;bel[cnt]=num;g[cnt]=tot;tail[cnt]=i;tot=1;}}for(int i=1;i<=cnt;i++){if(s[tail[i]]>s[tail[i]+1]){for(int j=tail[i]-g[i]+1;j<=tail[i];j++)printf("%d ",j);vis[i]=1;}}for(int i=cnt;i>=1;i--){if(vis[i])continue;for(int j=tail[i]-g[i]+1;j<=tail[i];j++)printf("%d ",j);}puts("");for(int i=1;i<=cnt;i++)vis[i]=0;}return 0;
}

2.CF1896E Permutation Sorting

题意

在这里插入图片描述
多组测试数据 1≤T≤101\le T\le 101T101≤n≤1051\le n\le 10^51n105

思路

注意是 (j mod k)+1(j\bmod k)+1(jmodk)+1。人话题意就是在环上,把还没回家的顺时针转一位,到一个没有已经回家了的人的家。(不理解的可以手玩一下呀)

考虑破环成链。记 iii 人现在的位置 posipos_iposi。若 posi≤ipos_i\le iposii 说明没有跨过 111 直接回家,否则就是跨过了 111。考虑画出当前位置到家的线段:

在这里插入图片描述
根据题目的操作,已经回家了的人(比如 555),就把他和他的家删掉。

111 要回家,理论上它要转 7−2=57-2=572=5 次,但是它中间有 333 条线段挡路——而这三条线段代表的 4,5,64,5,64,5,6 会比 111 先回家,少了 333 个挡路的 111 回家就只用转 222 次。333 同理,解决掉 444 个挡路的就只用转 6−4=26-4=264=2 次。

于是题目转化为,一段线段完全包含多少线段。每个人的答案就是其区间长度(理论上转的次数),减去包含线段数(已经回家被删除的人数)。

这是一个经典的二维数点问题。对于 [li,ri][l_i,r_i][li,ri]li≤lj≤rj≤ril_i\le l_j\le r_j\le r_ililjrjrijjj 的个数,可以先对右端点排序,在树状数组依次给每个线段的 lll+1+1+1。扫描线扫描每个右端点,统计 ≥li\ge l_ili 的个数即可。时间复杂度 O(nlog⁡n)O(n\log n)O(nlogn)

代码

#pragma GCC optimise(2)
#pragma GCC optimise(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
inline int read()
{int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;
}
inline void write(int x)
{ if(x==0){putchar('0');return;}int len=0,k1=x,c[10005];if(k1<0)k1=-k1,putchar('-');while(k1)c[len++]=k1%10+'0',k1/=10;while(len--)putchar(c[len]);
}
int id,Q,n,a[N];
unordered_map<int,int>pos;
struct term
{int l,r,id;
}p[N<<1];
bool cmp(term x,term y)
{if(x.r!=y.r)return x.r<y.r;return x.l>y.l;
}
int ANS[N];
struct BT
{int T[N<<1];int lowbit(int x){return x&(-x);}void add(int x,int k){for(int i=x;i<=2*n;i+=lowbit(i))T[i]+=k;}int query(int x){int ret=0;for(int i=x;i>=1;i-=lowbit(i))ret+=T[i];return ret;}void clean(){for(int i=1;i<=2*n;i++)T[i]=0;}
}B;
int main()
{freopen("home.in","r",stdin);freopen("home.out","w",stdout);scanf("%d%d",&id,&Q);while(Q--){n=read();for(int i=1;i<=n;i++){a[i]=read();pos[a[i]]=i;}int tot=0;for(int i=1;i<=n;i++){if(pos[i]<=i)p[++tot]=(term){pos[i],i,i},p[++tot]=(term){pos[i]+n,i+n,i};else p[++tot]=(term){pos[i],i+n,i};}sort(p+1,p+tot+1,cmp);for(int i=1;i<=tot;i++){ANS[p[i].id]=p[i].r-p[i].l-(B.query(p[i].r)-B.query(p[i].l-1));B.add(p[i].l,1);}for(int i=1;i<=n;i++)write(ANS[i]),printf(" ");puts("");for(int i=1;i<=tot;i++)B.add(p[i].l,-1);}return 0;
}

反思

要多观察啊!图都画出来了,其实不算难写的。

3.CF1889D Game of Stacks

题意

在这里插入图片描述
1≤n≤1051\le n\le 10^51n105∑ki≤106\sum k_i\le 10^6ki106

思路

~~赛时拼了一个 21pts 的暴力。~~这题思路还是太妙了,最终还是贺了。

考虑把一些重复的步骤给优化掉:这些操作相当于每个栈 iii 给栈顶 ci,topc_{i,top}ci,top 连边。我们把遍历到的点先用一个栈 loop 存下来,因为可能有一大段的元素答案会是同一个,记录答案数组 ansansans

  • ci,topc_{i,top}ci,top 为空,looplooploop 剩下的元素,答案都是 ci,topc_{i,top}ci,top
  • ci,topc_{i,top}ci,top 已经有了答案 ansci,topans_{c_{i,top}}ansci,toplooplooploop 剩下的元素,答案都是 ansci,topans_{c_{i,top}}ansci,top
  • ci,topc_{i,top}ci,top 曾被遍历过(loop 中有过),即构成了环。我们在 loop 中删去这个环,并把环上元素对应的栈都进行出栈操作。

这是好理解的,首先这个环的存在或否,对答案没有影响;其次无论从环上哪一个元素开始遍历,都会走过这个环。干脆就把这个无用的环永久删去了。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const ll N=2e5+9;
ll id,n;
stack<ll>stk[N];
ll loop[N],top; 
ll ANS[N];
bool vis[N];
ll dfs(ll u)
{if(ANS[u])return ANS[u];if(vis[u]){while(1){ll tem=loop[top--];vis[tem]=0;stk[tem].pop();if(u==tem)break;}}vis[u]=1;loop[++top]=u;if(stk[u].empty())return u;return dfs(stk[u].top());
}
int main()
{freopen("stack.in","r",stdin);freopen("stack.out","w",stdout);scanf("%lld%lld",&id,&n);for(int i=1;i<=n;i++){ll m,x;scanf("%lld",&m);for(int j=1;j<=m;j++){scanf("%lld",&x);stk[i].push(x);}}for(int i=1;i<=n;i++){if(!ANS[i]){top=0;ll t=dfs(i);for(int j=1;j<=top;j++)ANS[loop[j]]=t;}printf("%lld ",ANS[i]);}return 0;
}

4.CF1610G AmShZ Wins a Bet

http://www.dtcms.com/a/516321.html

相关文章:

  • CAN总线的物联网桥梁:以太网网关如何赋能工业4.0
  • C语言需要掌握的基础知识点之递归
  • 建设网站学什么wordpress zip格式
  • RFSoC在射频阵列信号采集分析中的应用
  • [Agent可视化] 会话管理 | Redis缓存 | PostgreSQL持久化 | 智能上下文处理
  • [Agent可视化] 编排工作流(Go) | Temporal引擎 | DAG调度器 | ReAct模式实现
  • 自定义时间服务器主机的时间通过ntp.aliyun.com主机同步时间
  • 做移动端网站设计做交通事故的网站
  • 【论文精读】EvalCrafter:文本到视频生成模型的全面评测框架
  • 普林尼与LLM提示词注入:AI安全防线的隐秘挑战
  • 撰写标书很难吗?用AI标书工具写标书,快速输出优质投标方案
  • HTML 实体起始符号详解
  • 什么网站可以做二建的题目贵州安顺建设主管部门网站
  • 海南美容网站建设旅游网站建设的总结
  • 通过npm run XXX命令生成uniapp的pages.json文件
  • HTML教程——1,css
  • H5响应式网站数据app外包公司推荐
  • ubuntu服务器无法识别所有显卡
  • Spring中常用的设计模式
  • 做网站是什么公司wordpress禁止 逍遥
  • 不定高虚拟列表性能优化全解析
  • 怎么免费建立自己的网站平台2018威胁网站检测平台建设
  • Python-封装、继承与重写
  • 新媒体培训班学费多少做网站和优化
  • 网站开发案例pdf工程造价信息价在什么网站查
  • Prometheus(一)—— Prometheus监控系统从入门到实战:理论与部署全指南
  • 使用宝塔面板docker部署https://github.com/imsyy/DailyHotApi项目
  • RHCE作业2
  • 乐云网站建设网站源码分享网
  • 发展历程 网站建设专业提供网站建设服务是什么