T1 嗑瓜子

解题思路

\(f_{i,j}\) 表示操作 \(i\) 次,拿走了 \(j\) 个瓜子的概率,转移就比较直接了:

\[f_{i+1,j+1}\leftarrow f_{i,j}\times\dfrac{n-j}{n+2\times j-i}
\]
\[f_{i+1,j}\leftarrow f_{i,j}\times\dfrac{3\times j-i}{n+2\times j-i}
\]

这里如果边界卡不准的话可能会出现使分母出现负数,注意一下,不然就会 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)的更多相关文章

  1. NOIP模拟83(多校16)

    前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...

  2. NOIP模拟92(多校25)

    前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...

  3. noip模拟题 2017.10.28 -kmp -Tarjan -鬼畜的优化

    题目大意 给定A串,选择A串的前lB个字符作为B串,再在B串后增加一个字符,问最长的相等的A串前缀和B串的后缀. Solution 1(KMP) 用1个奇怪的字符连接A串和B串,再用KMP求最长公共前 ...

  4. NOIP模拟84(多校17)

    T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...

  5. NOIP模拟85(多校18)

    前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...

  6. NOIP模拟86(多校19)

    T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...

  7. NOIP模拟88(多校21)

    前言 对于这套题的总体感觉就是难,然后就是自己很菜... 对于 T1 考试时只会一个最垃圾的背包,考完之后对于思路这一块也不是很顺利,大概这就是薄弱的地方吧. 然后 T2 是比较简单的一道题了,但是考 ...

  8. NOIP模拟96(多校29)

    T1 子集和 解题思路 大概是一个退背包的大白板,然而我考场上想复杂了,竟然还用到了组合数. 但是大概意思是一样的,有数的最小值一定是一个在 \(a\) 数组中存在的数字. 那么我们想办法除去它对应的 ...

  9. NOIP模拟99(多校31)

    T1 法阵 解题思路 原题3100,张口放 T1(出题人原话) 思维题,合法的情况其实就是上下两个梯形拼起来的样子. 他们的边界都是在 \(i\) 轴上面,但是不能相交. 于是我们可以尝试两者相交的纵 ...

  10. NOIP模拟 6.28

    NOIP模拟赛6.28 Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这 ...

随机推荐

  1. redis 简单整理——redis 的字符串基本结构和命令[二]

    前言 简单介绍一下redis的基本结构和命令. 正文 redis有5种基本结构: 字符串 哈希 列表 集合 有序集合 那么就来看下其基本命令吧. 通用命令键: keys * 查看全部键,一般不怎么用. ...

  2. 推荐一个页面引导库 driver.js

    页面引导功能是 web 开发中常见的一个功能.通过页面引导功能,你可以让用户第一时间熟悉你的页面功能.今天给大家推荐一个页面引导库 driver.js. 简介 driver.js 是一款用原生 js ...

  3. Windows 系统上如何安装 Python 环境(详细教程)

    Windows 系统上如何安装 Python 环境(详细教程) 目前,Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的.由于2.x版官方只维护到2020年,所以以3.x版作 ...

  4. Oracle 将字符中含有的字母或特殊字符去除并将字符串置换成数字

    将字符中含有的字母或特殊字符去除并将字符串置换成数字 将字符中含有的字母或特殊字符去除并将字符串置换成数字 to_number(nvl(TRANSLATE(u.scsqrbzl, 'qwertyuio ...

  5. maven报错:501 HTTPS Required

    maven报错:501 HTTPS Required 简单来说,如果报错中出现http://repo1.maven.org/maven2/的字样的话,那么大概率就是Maven仓库的设置里的地址有问题, ...

  6. sql多表分页查询【oracle】

    sql多表查询[oracle] 做个记录,好歹是写出来了,使用左连接的方法,进行四表查询,且使用rownum进行分页 把涉及内容的全部替换了,不过应该都看得懂,就不说了 select * from ( ...

  7. InnoDB之UNDO LOG介绍

    简介: undo log是InnoDB事务特性的重要组成部分.当对记录做增删改操作就会产生undo记录,undo记录会记录到单独的表空间中. 本文将从代码层面对undo log进行一个简单的介绍:主要 ...

  8. 如何构建企业出海的"免疫力"?深入解读阿里云CDN安全能力

    简介: 随着信息技术快速发展与应用,产业数字化和智能化趋势正日益加深,企业信息安全与防护被提升到前所有未有的高度.阿里云CDN经过10多年的技术发展时间,已逐步构筑一个边缘+云的安全网络立体防护体系, ...

  9. 快手基于 Flink 构建实时数仓场景化实践

    简介: 一文了解快手基于 Flink 构建的实时数仓架构,以及一些难题的解决方案. 本文整理自快手数据技术专家李天朔在 5 月 22 日北京站 Flink Meetup 分享的议题<快手基于 F ...

  10. [FAQ] html 的 select 标签 option 获取选中值的两种方式及区别

      Q: 对于一个 html 的 select 标签节点 class是module_select,获取选中值使用  $('.module_select').find('option:selected' ...