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) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这 ...
随机推荐
- Android、iOS、jenkins全自动化打包
主要流程思路[粗略讲处理思路,若遇到具体问题可留言交流]: 1.android的打包命令 2.ios的打包命令 3.jenkins的参数化构建 4.七牛的上传命令等 5.处理ipa的下载操作及ipa过 ...
- Log4j漏洞不仅仅是修复,更需要构建有效预警机制
简介:软件的漏洞有时不可避免,根据Gartner的相关统计,到 2025 年,30% 的关键信息基础设施组织将遇到安全漏洞.日志服务SLS,可帮助快速部署一个预警机制,使得漏洞被利用时可以快速发现并 ...
- [FAQ] 修改了Dockerfile 之后,运行 docker-compose up --force-recreate 时还是报之前构建时的错误?
因为 Docker Compose 的 --force-recreate 选项只会强制重新创建容器,而不会重新构建镜像. 因此,如果你修改了Dockerfile,需要确保重新构建新的镜像. 你可以 ...
- 防抖节流的含义使用场景及js实现原理
1.防抖:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时.代码实现重在清零 clearTimeout. 应用:登录,提交,浏览器窗口的resizes事件,文本编辑保存 <script ...
- [ABC345D] Tiling 位运算の极致运用
[ABC345D] Tiling 原题解地址:Editorial by Kiri8128 神写法. 将 \(H \times W\) 的网格展开为 \(H \times (W + 1)\) 的序列, ...
- element Tree 树形控件
文档地址 https://element.eleme.cn/#/zh-CN/component/tree 代码地址 https://gitee.com/wBekvam/vue-shop-admin/b ...
- ansible(7)--ansible的file模块
1. file模块 功能:为被控端创建文件或目录,设定权限属性: 主要参数如下: 参数 说明 path 指定远程服务器的路径,也可以写成'dest','name' state 状态,可以将值设定为di ...
- XML Schema(XSD)详解:定义 XML 文档结构合法性的完整指南
XML Schema描述了 XML 文档的结构.XML Schema语言也称为 XML Schema Definition(XSD). <?xml version="1.0" ...
- Django 安全性与防御性编程:如何保护 Django Web 应用
title: Django 安全性与防御性编程:如何保护 Django Web 应用 date: 2024/5/13 20:26:58 updated: 2024/5/13 20:26:58 cate ...
- 密码学—Vigenere破解Python程序
文章目录 概要 预备知识点学习 整体流程 技术名词解释 技术细节 小结 代码 概要 破解Vigenere需要Kasiski测试法与重合指数法的理论基础 具体知识点细节看下面这两篇文章 预备知识点学习 ...