Edu Round 170 Review

news/2024/10/18 17:54:21/文章来源:https://www.cnblogs.com/Hanggoash/p/18474771

Edu Round 170 Review

A

分析

一个很显然的根据前缀划分的贪心,直接指针模拟就好了。

Code

#include<bits/stdc++.h>
using namespace std;
int main()
{int t;cin>>t;while(t--){string a,b;cin>>a>>b;int l1=a.length(),l2=b.length();int p=0;while(p<l1&&p<l2&&a[p]==b[p])p++;if(p>0)p--;cout<<l1+l2-p<<'\n';}}

B

分析

打表就发现需要输出的就是 \(2^n\) ,然而这道题我卡了十多分钟,实在是有点sb了。

具体证明的话可以用数学归纳法,也可以直接证明,都是比较容易的。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=1e9+7;
inline int power(int a,int b)
{int ans=1;while(b){if(b&1)ans=ans*a%MOD;a=a*a%MOD;b>>=1;}return ans%MOD; 
}
const int N=2e5+1;
int t,n[N],k[N];
inline void solve()
{cin>>t;for(int i=1;i<=t;++i)scanf("%d",&n[i]);for(int i=1;i<=t;++i)scanf("%d",&k[i]),printf("%lld\n",power(2,k[i]));
}
signed main()
{solve();
}

C

分析

其实思路上面很简单,只需要以每个数为开头贪心地连续去选择尽可能多的数字就可以了。

注意这样做是 \(O(n^2)\) 的,那么考虑如何在枚举的时候快速地从现在的答案推知下一个答案。

很容易想到一个简化的莫队,从 \([l,r]\)\([l+1,r+1]\) ,实际上只是增加了一个数,去除了一个数而已,通过增量就可以计算出来。

边界写错了吃了两发罚时(实际上可以不需要去重的,所以说本人的找屎能力真的强)。

又成功地在模拟题上面写出了一道屎山代码。。。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
template<typename T>inline void re(T &x)
{x=0;int f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x*=f;
}
template<typename T>inline void wr(T x)
{if(x>9)wr(x/10);putchar(x%10^48);
}
int t,n,k,a[200010];
pair<int,int>b[200010];
inline void solve()
{re(n),re(k);for(register int i=1;i<=n;++i)re(a[i]);sort(a+1,a+n+1);a[n+1]=0;int cnt=1,p=0;for(register int i=1;i<=n;++i){if(a[i]!=a[i+1]){b[++p].first=a[i];b[p].second=cnt;cnt=1;}else cnt++;}int ans=-1,lasl=0,lasr=0;int lasans=0;for(register int i=1;i<=p;++i){if(!lasans){int p1=i+1;lasans=b[i].second;while(p1<=p&&p1-i+1<=k&&b[p1].first-b[p1-1].first==1)lasans+=b[p1++].second;ans=max(ans,lasans),lasl=i,lasr=p1-1;}else{int nowr=lasr+i-lasl;if(b[nowr].first-b[nowr-1].first!=1||nowr>p){i=nowr-1;lasans=lasl=lasr=0;continue;}lasans-=b[i-1].second,lasans+=b[nowr].second;ans=max(ans,lasans);}}wr(ans),putchar('\n');
}
signed main()
{re(t);while(t--)solve();return 0;
}	

D

分析

因为实现能力太差,C做了一个小时,导致D只有不到二十分钟的时间了,大概扫过去想了一个很骚的做法,就是倒叙枚举然后贪心地选择贡献即可,结果发现题看错了。。。

这种涉及到抉择的题发现贪心是假的,那肯定就是DP了。

那其实阶段和状态也很容易设计出来。

定义 \(dp[i][j]\) 为前 \(i\) 个数字 选择了 \(j\) 点智力加点能够获得的分数(注意此时体力的加点一定是唯一确定的,因此我们没有必要单独开一维来单独记录,前提是我们需要统计出来一个数组来记录任意某个位置 \(pos\) 之前一共出现了多少个 \(0\) ) 。

那么转移方程也非常的水到渠成:

如果 \(a_i=0\) ,那么所有的 \(dp[i][j]=\max(dp[i-1][j],dp[i-1][j-1])\)

如果 \(a_i>0\) ,那么所有的 \(dp[i][j](j\ge a_i)=dp[i-1][j]+1\)

如果 \(a_i<0\) ,那么所有的 \(dp[i][j](j\le sum0-(-a_i))=dp[i-1][j]+1\)

注意到我们会多次执行区间加的操作,实际上你可以写一个线段树,或者是树状数组,然而都太麻烦或者不好实现(对我来说)。

我们可以直接采用差分数组,但是缺陷就在于,虽然可以多次进行区间加法,但是一只能统计一次。观察到这道题 \(m\) 的数据范围非常小,所以每次遇到一个 \(0\) 之前,我们就暴力地统计一遍差分数组,然后加到 \(dp\) 数组里面,而后进行 \(0\) 处该进行的转移,再把差分数组清零,重新进行后续的区间加操作即可。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{x=0;int f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x*=f;
}
template<typename T>inline void wr(T x)
{if(x>9)wr(x/10);putchar(x%10^48);
} 
const int N=2e6+100;
int a[N],dp[5010];
int n,m;
int s[5010];
inline void add(int l,int r,int v)
{s[l]+=v,s[r+1]-=v;
}
inline void	calcsum()
{for(int i=1;i<=m;++i)s[i]+=s[i-1];for(int i=0;i<=m;++i)dp[i]+=s[i],s[i]=0;
}	
inline void pre()
{re(n),re(m);for(register int i=1;i<=n;++i)re(a[i]);
}
inline void solve()
{int sum0=0;for(register int i=1;i<=n;++i){if(a[i]==0){calcsum();for(register int j=++sum0;j>=1;--j)dp[j]=max(dp[j],dp[j-1]);	}else if(a[i]>0){if(sum0<a[i])continue;add(a[i],sum0,1);}else{if(sum0<abs(a[i]))continue;add(0,sum0+a[i],1);					}}calcsum();int ans=-1;for(register int i=0;i<=m;++i)ans=max(ans,dp[i]);wr(ans);
}
int main()
{pre();solve();return 0;
}
/*
dp[i][j] 前i个数字  拥有 j 点智力可以获得的分数all dp[i][j]=dp[i-1][j];
if(0)dp[i][j]=max dp[i][j],dp[i-1][j-1];
if(+)dp[i][j]=add(a[i],sum0[i],1);
if(-)  dp[i][j]=add(0,sum0[i]+a[i],1);写的时候的问题:前缀和之后没有给dp 0加上去统计差分 和 进行 O(m) 转移的顺序搞反了  
*/

E

非常好的一道计数题,让我“温习“了一下在高二的时候学习过的卡特兰数。

前置知识

卡特兰数

定义背景

由于这一类组合数对于实际问题有意义,所以才会被单独讨论,它适用于如下情况:

  1. \(n\) 个人排成一行进入剧场。入场费 5 元。其中只有个 \(n\) 人有一张 5 元钞票,另外人 \(n\) 只有 10 元钞票,剧院无其它钞票,问有多少种方法使得只要有 10 元的人买票,售票处就有 5 元的钞票找零?
  2. 有一个大小为 \(n\times n\) 的方格图开始每次都只能向右或者向上走一单位,不走到对角线上方(但可以触碰)的情况下到达右上角有多少可能的路径?
  3. 在圆上选择 \(2n\) 个点,将这些点成对连接起来使得所得到的条 \(n\) 线段不相交的方法数?
  4. 对角线不相交的情况下,将一个凸多边形区域分成三角形区域的方法数?
  5. 一个栈(无穷大)的进栈序列为 \(1-n\) 有多少个不同的出栈序列?
  6. \(n\) 个结点可构造多少个不同的二叉树?
  7. \(n\)\(+-1\) 组成的序列,满足任意前缀和非负,有多少种构造方案?

公式

  1. \(H_n=\frac{C_{2n}^{n}}{n+1}\)

  2. \(H_n=C_{2n}^n-C_{2n}{n-1}\)

  3. \(H_n=H_{n-1}\times \frac{4n-2}{n+1}\)

  4. DP的方式求(卡特兰数实际上是一个匹配的过程)

    定义 \(f_{i,j}\) 为,前 \(i\) 个数,剩下了 \(j\) 个没有匹配的方案数,那么最后的答案就是 \(f_{2n,0}\)

    转移方程也很好写,

    ​ $$f_{i,j}+=f_{i-1,j-1}$$ 当前作为左括号。

    ​ $$f_{i,j}+=f_{i-1,j+1}$$ 当前作为右括号并和一个左括号匹配。

分析

我们钦定两个人分别为 \(A,B\) ,明显的是这道题中 \(1\) 是一个比较特殊的花色,对于其他普通的花色,我可以两个人选的一样,然后两个人内部进行分配使得 \(A\) 总是赢;也可以暂时让 \(B\) 的牌多于 \(A\) ,后面拿若干张的 \(1\) 来进行弥补性配对。

我们考虑如何进行这个计数DP。

对于 \(1\) 花色特殊考虑,我们先不处理它。

对于其他任意一种颜色,我们应用第一种分配策略时,把 \(m\) 张牌均分给两个人,首先假定这个 \(1-m\) 的序列已经降序排列好了。

那么我们从大到小以此给两人分配,发现如果任何时刻,我给 \(B\) 分配的牌都必须要小于等于给 \(A\) 分配的牌,才能够满足题设条件。

那么这实际上就是一个卡特兰数 \(H_{\frac{m}{2}}\),可以比较性地发现。

我们应用第二种分配时,很容易想到先选出 \(k\) (偶数)个来不进行配对之后和 \(1\) 配,然后剩下的 \(m-k\) 个按照卡特兰数配对。

看起来没什么问题,实际上也确实没问题,但在这道题的计数规则下就是错误的,由于我选出来不配对的几个数实际上是归于 \(A\) 的,这就意味着分别属于 \(A\) 的参与匹配的集合A的暂时不参与匹配集合 的两个数,可能会被重复计算。

反观我们用 DP 求卡特兰数的过程,实际上就已经把这里我们需要的答案给计算出来了,我们想要剔除 \(k\) 个,然后剩下的配对,那么方案数就是上面提到的 \(f_{i,k}\) ,那么我们转移起来也就相对来说很好想了。

\(dp_{i,j}\) 的定义是 前 \(i\) 个花色 (不包括 \(1\) ),一共剩下了 \(j\) 个的方案数。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=998244353,N=600;
int dp[N][N],n,m;
inline int power(int a,int b)
{int ans=1;while(b){if(b&1)ans=ans*a%MOD;a=a*a%MOD;b>>=1;}return ans%MOD;
}
inline void garbage_bin()
{int C[N][N],catalan[N];for(register int i=0;i<=m;++i){C[i][0]=1;for(register int j=1;j<=i;++j)C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;}catalan[0]=1;for(register int i=1;i<=m;i++)catalan[i]=catalan[i-1]*(4*i-2)%MOD*power(i+1,MOD-2)%MOD;
}
int cat[N][N]; 
void pre()
{cin>>n>>m;cat[0][0]=1;for(register int i=1;i<=m;++i)for(register int j=0;j<=m;++j){if(j-1>=0)cat[i][j]+=cat[i-1][j-1],cat[i][j]%=MOD;cat[i][j]+=cat[i-1][j+1],cat[i][j]%=MOD;}
}
void solve()
{dp[0][0]=1;for(register int i=1;i<=n-1;++i){for(register int j=0;j<=m;j+=2)for(register int k=0;k<=j;k+=2)dp[i][j]+=dp[i-1][j-k]*cat[m][k]%MOD,dp[i][j]%=MOD;	}int ans=0;for(register int j=0;j<=m;j+=2)ans+=cat[m][j]*dp[n-1][j]%MOD,ans%=MOD;cout<<ans;		
}
// 4  3 2 1
// 12A + 4A3B
// 13A + 4A2B
// 14A + 3A2B
// 23A + 4A1B
// 24A + 3A1B
// 34A + 2A1B 
//dp 4 2=dp 3 1 (2)+dp3 3 (1)
signed main()
{pre();solve();return 0;
} 

好久没有写过题解了。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/816984.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android8,reactnative中webView传的token,vue中获取不到是怎么回事?

rn代码是这样的,要在vue页面获取到tokenvue中是这样写的,安卓9以上都能得到,就是8获取不到有没有大佬帮忙看看,跪谢!!!!

实时同步服务

1 实时同步应用场景通过rsync+定时任务实现定时备份/同步 对于NFS我们需要进行实时同步2 实时同步工具选型实时同步工具 特点 选型inotify工具+脚本inotify监控指定的目录,监控 目录下是否有变化,显示变化了的文件. 通过rsync服务端与客户端传送,书写脚本.不推荐,有性能问题.se…

五款免费报表工具推荐:山海鲸报表、Tableau 等优劣对比

在当今数据驱动的时代,报表工具已经成为各类企业进行决策和管理的重要工具。无论是大中型企业还是小微企业,能够快速、高效地生成可视化报表,洞察业务运营情况,已经成为提升竞争力的关键。今天为大家挑选了5款非常优秀的报表软件,并且详细分析了它们的优缺点,希望能够帮助…

DevExpress隐藏列表中显示的加号+

GridView1.OptionsDetail.EnableMasterViewMode = False

人大金仓kingbase部署

环境准备: 系统版本:CentOS Linux release 7.9.2009 (Core) 硬件配置:4C4G200G 安装包准备:KingbaseES_V008R006C008B0020_Lin64_install.iso https://www.kingbase.com.cn/xzzx/index.htmlicense准备:license_企业版.zip https://www.kingbase.com.cn/xzzx/index.htm计划…

从深海探测到海洋强国:数字孪生助力海洋装备跨越式发展

浮力调节系统作为涉及潜水的海洋设备的关键部件,能够为潜水器提供稳定悬浮的深度控制,并能根据工作深度的不同通过改变浮力来带动潜水器上浮或下潜。海洋广袤无垠,蕴藏着丰富的资源。近现代以来,人类使用各种手段探索海洋探索,广袤无垠的海洋与人类的生活越来越紧密,至少…

python - 分享绕过验证码登录的方法

一、通过webdriver启动浏览器:二、添加cookie:三、切换到目标地址: # This is a sample Python script. from selenium import webdriver import time # Press Shift+F10 to execute it or replace it with your code. # Press Double Shift to search everywhere for clas…

通义灵码上线一周年:超 600 万下载量,国内用户规模第一,新功能有奖测评

通义灵码,是基于通义大模型的 AI 研发辅助工具,包含 AI 编码助手和 AI 程序员。其中,AI 编码助手为开发者写代码、补代码、写注释、写单测、写代码优化和排查问题,是开发者的编码搭子!通义灵码,是基于通义大模型的 AI 研发辅助工具,包含 AI 编码助手和 AI 程序员。 其中…

mysql当数据库发现了慢sql怎么定位?--待验证

1、应用侧生成链路id。 使用skywalking 2、mybatis写拦截器,sql里面加入链路id `@Intercepts({ @Signature( type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class} ) }) public class SqlStatementInterceptor implements…

Echarts 关于formatter的使用

其实这个 formatter 很实用哈,可以自定义很多格式内容,尤其是提示和图例那边,还有柱状图的内容啥的 官网给的案例啊,看不懂哈哈哈 来点自己的小经验,几乎都可以实用啊,而且可以搭配rich自定义样式, 1、字符串模板 最简单的就是这样使用的,关于参数,这个官网给答案了,…

Higress 重磅更新:AI 能力全面开源,云原生能力再升级

Higress 最新的 1.4 版本基于为通义千问,以及多家云上 AGI 厂商客户提供 AI 网关的积累沉淀,开源了大量 AI 原生的网关能力。作者:澄潭、钰诚 新版本简介 Higress 最新的 1.4 版本基于为通义千问,以及多家云上 AGI 厂商客户提供 AI 网关的积累沉淀,开源了大量 AI 原生的网…

普天同悲

谨记,谨记。世人若学我,当如堕魔道。