NOIP模拟95(多校28)
T1 嗑瓜子
解题思路
\(f_{i,j}\) 表示操作 \(i\) 次,拿走了 \(j\) 个瓜子的概率,转移就比较直接了:
\]
\]
这里如果边界卡不准的话可能会出现使分母出现负数,注意一下,不然就会 RE 获得 50pts 的高分。。。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e3+10,mod=998244353;
int n,ans,f[N*3][N],inv[N*3];
void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int Inv(int x){if(x>=0)return inv[x];return 0;}
#undef int
int main()
{
#define int long long
freopen("eat.in","r",stdin); freopen("eat.out","w",stdout);
n=read(); f[0][0]=1; inv[1]=1;
for(int i=2;i<=3*n;i++) inv[i]=inv[mod%i]*(mod-mod/i)%mod;
for(int i=0;i<3*n-2;i++)
for(int j=0;j<=min(i,n-1);j++)
add(f[i+1][j+1],f[i][j]*(n-j)%mod*Inv(n+2*j-i)%mod),
add(f[i+1][j],f[i][j]*(3*j-i)%mod*Inv(n+2*j-i)%mod);
for(int i=n;i<=3*n-2;i++) add(ans,f[i][n]*i%mod);
printf("%lld",ans);
return 0;
}
T2 第 k 大查询
解题思路
在区间 \([l,r]\) 中 \(s_i\) 是 k 大值的情况当且仅当 \([l,r]\) 中有 \(k-1\) 个大于 \(s_i\) 的数字。
那么我们就可以维护一下每一个数字前面比 \(s_i\) 大的 k 个值以及后面比 \(s_i\) 大的 k 个值,然后指针扫一遍就好了。
那么问题就变成的如何维护一个数前面以及后面的比他大的值,我们可以选择 双向链表 来实现。
对于值域上面按照原序列顺序建一个链表,然后从小往大计算值的贡献,每次计算完之后直接删掉这个值就可以了。
code
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=5e5+10;
int n,m,t1,t2,a[N],b[N],s[N],id[N],fro[N],nxt[N];
ll ans;
#undef int
int main()
{
#define ll long long
freopen("kth.in","r",stdin); freopen("kth.out","w",stdout);
n=read(); m=read(); id[s[0]=n+1]=0; id[s[n+1]=n+2]=n+1;
for(int i=1;i<=n;i++) s[i]=read(),id[s[i]]=i;
for(int i=1;i<=n;i++) fro[s[i]]=s[i-1],nxt[s[i]]=s[i+1];
for(int i=1;i<=n;i++)
{
t1=t2=-1;
for(int j=i;j&&t1<m;j=fro[j]) a[++t1]=id[j];
for(int j=i;j&&t2<m;j=nxt[j]) b[++t2]=id[j];
for(int j=1;j<=t1;j++) if(m-j<t2) ans+=1ll*i*(a[j-1]-a[j])*(b[m-j+1]-b[m-j]);
int tmp1=fro[i],tmp2=nxt[i]; fro[tmp2]=tmp1,nxt[tmp1]=tmp2;
}
printf("%lld",ans);
return 0;
}
T3 树上路径
解题思路
一道及其难调的树形 DP ,需要维护好多的值QAQ。。。
\(f_i\) 表示 \(i\) 节点向子树中可以延伸到最长路径。
\(dis_i\) 表示 \(i\) 节点为根节点的子树中最长的路径。
\(g_i\) 表示 除了以 \(i\) 节点为根的子树,\(fa_i\) 为路径的一个端点可以延伸到最长路径。
\(dp_i\) 表示删去 \(i\rightarrow fa_i\) 这一条边 \(fa_i\) 所在部分的最长路径。
答案显然就是对于每一个边枚举它断掉的情况,然后记录两个部分的直径(假设深度较大的是 \(x\),两个直径就是 \(dis_x\) 和 \(dp_x\))最后再给答案取一个后缀 \(\max\) 。
对于 \(f_i\) 还有 \(dis_i\) 数组的计算其实就是 DP 求树的直径的打法。
对于 \(g_i\) 数组的直接记录一个子树内的最大值以及次大值就好了。
对于 \(dp_i\) 数组的转移需要记一下关于 \(f_i\) 的最大值次大值以及次次大值,因为计算答案的时候需要算上除了自己这一棵子树,它的父亲节点的其他子树之间的最长路径所拼起来的贡献。
大概三遍 DFS 就解决了。。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=5e5+10;
int n,Ans,ans[N],f[N],g[N],dis[N],dep[N],mx[N],sec[N],tri[N],dp[N];
int tot=1,head[N],ver[N<<1],nxt[N<<1];
bool vis[N];
void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i]; if(to==fa) continue; dfs(ver[i],x);
dis[x]=max(dis[x],max(dis[to],f[x]+f[to]+1));
f[x]=max(f[x],f[to]+1);
if(f[to]+1>mx[x]) tri[x]=sec[x],sec[x]=mx[x],mx[x]=f[to]+1;
else if(f[to]+1>sec[x]) tri[x]=sec[x],sec[x]=f[to]+1;
else tri[x]=max(tri[x],f[to]+1);
}
}
void dfs2(int x,int fa)
{
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i]; if(to==fa) continue;
if(f[to]+1==mx[x]) g[to]=max(g[x]+1,sec[x]+1);
else g[to]=max(g[x]+1,mx[x]+1); dfs2(ver[i],x);
}
}
void dfs3(int x,int fa)
{
int num1=0,num2=0;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i]; if(to==fa) continue;
if(num1<dis[to]+1) num2=num1,num1=dis[to]+1;
else num2=max(num2,dis[to]+1);
}
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i]; if(to==fa) continue; dp[to]=g[x];
if(f[to]+1==mx[x]) dp[to]=max(dp[to],sec[x]);
else dp[to]=max(dp[to],mx[x]);
}
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i]; if(to==fa) continue;
dp[to]=max(dp[to],dis[to]+1==num1?num2:num1);
if(f[to]+1==mx[x]) dp[to]=max(dp[to],sec[x]+g[x]+1);
else dp[to]=max(dp[to],mx[x]+g[x]+1);
if(f[to]+1==mx[x]) dp[to]=max(dp[to],sec[x]+tri[x]+1);
else if(f[to]+1==sec[x]) dp[to]=max(dp[to],mx[x]+tri[x]+1);
else dp[to]=max(dp[to],mx[x]+sec[x]+1); dfs3(to,x);
}
}
#undef int
int main()
{
#define int long long
freopen("tree.in","r",stdin); freopen("tree.out","w",stdout);
n=read();
for(int i=1,x,y;i<n;i++)
x=read(),y=read(),
add_edge(x,y),add_edge(y,x);
dfs(1,0); dfs2(1,0); dfs3(1,0);
for(int i=1;i<n;i++)
{
int x=ver[i<<1],y=ver[i<<1|1]; if(dep[x]>dep[y]) swap(x,y);
int num1=dis[y]+1,num2=dp[y];
ans[num1]=max(ans[num1],num2); ans[num2]=max(ans[num2],num1);
}
for(int i=n;i>=1;i--) ans[i]=max(ans[i],ans[i+1]),Ans+=ans[i];
printf("%lld",Ans);
return 0;
}
T4 糖
解题思路
思路特别妙,我们先在每一个点把背包填满,那么如果到了最后还没有用掉的话可以直接按照原价卖出计算贡献。
如果背包中糖果的买入价格小于当前点的卖价,我们就可以当做他们是以当前点卖价买进来的,于是可以直接更改他们的价格但是不对答案造成贡献。
那么如果背包中糖果的买入价格大于当前点的买入价,我们就可以直接替换掉这些糖果。
最后再把背包填满,然后计算路径上的删掉的糖果,优先吃掉买的代价较小的糖果。
上述操作都可以通过 单调队列 来实现。
code
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10;
int n,m,head=1,tail,ans,hav,s[N],a[N],b[N];
struct Node{int val,cnt;}q[N];
#undef int
int main()
{
#define int long long
freopen("candy.in","r",stdin); freopen("candy.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++) s[i]=read();
for(int i=0;i<n;i++) a[i]=read(),b[i]=read();
for(int i=0;i<n;i++)
{
int sum=0,dis=s[i+1]-s[i];
while(head<=tail&&q[head].val<=b[i]) sum+=q[head++].cnt;
if(sum) q[--head]=(Node){b[i],sum};
while(head<=tail&&q[tail].val>=a[i])
ans-=q[tail].val*q[tail].cnt,hav-=q[tail--].cnt;
if(hav<m) q[++tail]=(Node){a[i],m-hav},ans+=a[i]*(m-hav),hav=m;
while(head<=tail&&dis>=q[head].cnt) dis-=q[head++].cnt;
if(dis) q[head].cnt-=dis; hav-=s[i+1]-s[i];
}
while(head<=tail) ans-=q[head].cnt*q[head].val,head++;
printf("%lld",ans);
return 0;
}
NOIP模拟95(多校28)的更多相关文章
- NOIP模拟83(多校16)
前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...
- NOIP模拟92(多校25)
前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...
- noip模拟题 2017.10.28 -kmp -Tarjan -鬼畜的优化
题目大意 给定A串,选择A串的前lB个字符作为B串,再在B串后增加一个字符,问最长的相等的A串前缀和B串的后缀. Solution 1(KMP) 用1个奇怪的字符连接A串和B串,再用KMP求最长公共前 ...
- NOIP模拟84(多校17)
T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...
- NOIP模拟85(多校18)
前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...
- NOIP模拟86(多校19)
T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...
- NOIP模拟88(多校21)
前言 对于这套题的总体感觉就是难,然后就是自己很菜... 对于 T1 考试时只会一个最垃圾的背包,考完之后对于思路这一块也不是很顺利,大概这就是薄弱的地方吧. 然后 T2 是比较简单的一道题了,但是考 ...
- NOIP模拟96(多校29)
T1 子集和 解题思路 大概是一个退背包的大白板,然而我考场上想复杂了,竟然还用到了组合数. 但是大概意思是一样的,有数的最小值一定是一个在 \(a\) 数组中存在的数字. 那么我们想办法除去它对应的 ...
- NOIP模拟99(多校31)
T1 法阵 解题思路 原题3100,张口放 T1(出题人原话) 思维题,合法的情况其实就是上下两个梯形拼起来的样子. 他们的边界都是在 \(i\) 轴上面,但是不能相交. 于是我们可以尝试两者相交的纵 ...
- NOIP模拟 6.28
NOIP模拟赛6.28 Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这 ...
随机推荐
- 重新点亮linux 命令树————screen 命令和系统日志[二十四]
前言 简单介绍一下screen 正文 因为我们终端关闭后,终端就消失了,故而希望有终端保持. 1.yum install screen 进行安装. 2.使用screen 进行进入 3.然后打开tail ...
- Django3.0连接数据库注意点
需先在应用下的__Init__.py文件中配置 import pymysqlpymysql.version_info=(1, 3, 13, 'final', 0) # 3.0时需要pymysql.in ...
- Android、iOS、jenkins全自动化打包
主要流程思路[粗略讲处理思路,若遇到具体问题可留言交流]: 1.android的打包命令 2.ios的打包命令 3.jenkins的参数化构建 4.七牛的上传命令等 5.处理ipa的下载操作及ipa过 ...
- 使用Git向Gitee仓库推送项目的完整流程
1.安装git 如果没有特殊需求,直接下一步即可:安装链接如下:Git - Downloads (git-scm.com) 2.在Gitee上新建仓库,初始化仓库 3.保存仓库的链接,如下图标记所示 ...
- PolarDB-X 全局Binlog解读之性能篇(上)
简介: 本篇来介绍一下PolarDB-X全局binlog在性能方面的一些设计和思考,先通过几个实际的测试案例来展示全局binlog的性能情况,然后结合这些案例来深入讲解全局binlog关于优化的故事. ...
- 科普达人丨漫画图解SGX加密计算黑科技
介: 运行态的数据也可以被加密,实现数据可用不可见. 01 从一场朋友圈的"赛富"说起 最近,小明买基金赚了不少钱,开始膨胀了,开始在朋友圈里晒豪车.晒爱马仕.小红表示不服,&qu ...
- Flagger on ASM——基于Mixerless Telemetry实现渐进式灰度发布系列 3 渐进式灰度发布
简介: 作为CNCF[成员](https://landscape.cncf.io/card-mode?category=continuous-integration-delivery&grou ...
- 重磅发布 阿里云数据中台全新产品DataTrust聚焦企业数据安全保障
简介: DataTrust(隐私增强计算产品)是基于阿里云底层多项基础安全能力,经过阿里云数据中台丰富的客户业务实践,构建的一款为企业数据安全流通的产品. 随着包括零售.制造.金融等多行业数字化转型加 ...
- dotnet 读 WPF 源代码笔记 为什么自定义的 UserControl 用户控件不能跨程序集继承
从设计上,用户控件 UserControl 就不是一个合适用来多次继承的类型,更不要说进行跨程序集继承自定义的 UserControl 用户控件.对于大部分的用户控件来说,都是采用组合现有的控件来实现 ...
- 使用 Silk.NET 创建 OpenGL 空窗口项目例子
本文告诉大家如何使用 Silk.NET 创建 OpenGL 空窗口项目.在 dotnet 基金会下,开源维护 Silk.NET 仓库,此仓库提供了渲染相关的封装逻辑,包括 DX 和 OpenGL 等等 ...