2021年牛客暑期多校训练营5
2021年牛客暑期多校训练营5
A Away from College(待)
题意:
题解:
注意:
代码:
B Boxes
题意:
已知有n个箱子,每个箱子里面装的可能是白球也可能是黑球,现在可以让你打开箱子看一看,每个箱子i打开都需要w[i]的费用,也可以获得一个提示,得知之后的黑球个数,需要费用C,现在求最小的费用是多少
题解:
我们可以考虑先把盒子打开,当然费用当然是从小到大算起,求一个前缀和,w[i]表示的就是打开了i个盒子一共所需要的费用。之后再索要提示,只要剩下的n-i个小球如果全是黑球那么就猜测成功,概率就是p=所以期望ans+=w[i]*p ans=min(ans+C,w[n]);和全部打开的费用进行比较即可
注意:
我当时很多公式都推出来了,就是没有把前缀和考虑进去,结果自然就WA了 😨
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
int n;double C;
double w[maxn];double p[maxn];
int main()
{
cin>>n>>C;
for(int i=1;i<=n;i++)cin>>w[i];
sort(w+1,w+n+1);
for(int i=1;i<=n;i++)w[i]+=w[i-1];//前缀和维护,表示打开了i个箱子所需要的费用
double ans=0,p=0.5;
for(int i=n-1;i>=1;i--){
ans+=p*w[i];
p*=0.5;
}
cout<<fixed <<setprecision(6)<<min(ans+C,w[n]);
return 0;
}
C Cheating and Stealing(待)
题意:
题解:
注意:
代码:
D Double Strings
题意:
给定两个字符串a,b,从a和b中各选一个长度为n的子串,满足for exists i in(1,n) s[i]<t[i] for all j in(1,i) s[j]=t[j] 求s,t的组合对数
题解:
详情参考 就是对于字符串s,t而言,在第x个位置存在大小关系,x之前是公共前缀,x之后是随意的顺序
(公共前缀): 二维DP有f[i] [j] :A的前i位和B的前j位构成的公共子序列的数量
f[i] [j]=f[i] [j-1]+f[i-1] [j]- f[i-1] [j-1];
if(s[i]==s[j]) f[i] [j]+= f[i-1] [j-1]+1;
剩下的就是组合数的计算假设A剩下了x个字母,B剩下了y个字母有
(假设x<y)
二项式定理
也就是说的系数就是我们想要求的组合数
这里用上一个乘法逆元即可
费马小定理 有 则 那么可以用来代替作为a的逆元 即
我们可以通过快速幂来求 再进行线性递推得到其他阶乘的逆元
证明如下:
注意:
当前缀为0的时候,有算作一种可能,所以每次都需要加上1,再去乘以组合数
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
typedef long long ll;
ll f[N][N];
ll inv[N<<1],fact[N<<1];
const ll p=1e9+7;
char s[N],t[N];
ll qpow(ll a,ll b,ll p)
{
ll ans=1,base=a;
while(b)
{
if(b&1)ans=(ans*base)%p;
base=(base*base)%p;
b>>=1;
}
return ans;
}
void init(int n)
{
fact[0]=1;
for(int i=1;i<=n;i++){
fact[i]=fact[i-1]*i%p;
}//阶乘
inv[n]=qpow(fact[n],p-2,p);
for(int i=n-1;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%p;
}
ll C(ll n,ll m)
{
if(m>n)return 0;
return fact[n]*inv[m]%p*inv[n-m]%p;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>s+1>>t+1;
int n=strlen(s+1),m=strlen(t+1);
init(max(n,m)<<1);//后面要求C(n+m,n)这种较大的数,所以需要扩大到2倍的范围
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=(f[i-1][j]+f[i][j-1]-f[i-1][j-1]+p)%p;
if(s[i]==t[j])f[i][j]=(f[i][j]+f[i-1][j-1]+1)%p;
}
}
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i]<t[j])
ans=(ans+(1+f[i-1][j-1])*C(n-i+m-j,m-j))%p;
}
}
cout<<ans;
return 0;
}
E Eert Esiwtib(待)
题意:
题解:
注意:
代码:
F Finding Points(待)
题意:
题解:
注意:
代码:
G Greater Integer, Better LCM(待)
题意:
题解:
注意:
代码:
H Holding Two
题意:
输出一个行不能连着三个相同,列也不能连着三个相同的n行m列的01矩阵
题解:
构造成
0011001100...
1100110011...
0011001100...
A[i] [j]=(i+j/2)%2 输出n*m即可
注意:
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if((i+j/2)%2==0)printf("0");
else printf("1");
}
printf("\n");
}
return 0;
}
I Interval Queries(待)
题意:
题解:
注意:
代码:
J Jewels
题意:
给定n个点的xi轴yi轴坐标,每只气球会以vi/s的速度飞起来,人的起点在(0,0,0),问人把所有的气球都摘下来要走的最长距离是多少
题解:
详情参考 这是一个最小权值匹配问题,用时间和每一个气球进行匹配,匹配好ans+=dis[match[i]] [i] 输出即可,注意,因为这是一个最小权匹配,所以找到的是最小值,而且dis初始化的时候也要用负数,最后输出-ans即可
注意:
注意long long ,INF开到long long 的较大数
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=310;
typedef long long ll;
#define INF ((1ll)<<62)
int vis[N],match[N],pre[N];
ll la[N],ra[N],slack[N],dis[N][N];
int n;
void bfs(ll u)
{
ll x,y=0,yy,delta;
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++)slack[i]=INF;
match[y]=u;
while(true)
{
x=match[y],delta=INF;vis[y]=1;
for(int i=1;i<=n;i++){
if(vis[i])continue;
if(slack[i]>la[x]+ra[i]-dis[x][i]){//y的期望和i的期望匹配的能更小
slack[i]=la[x]+ra[i]-dis[x][i];
pre[i]=y;//i和y匹配
}
if(slack[i]<delta){
delta=slack[i];
yy=i;//记录下最小的
}
}//每次挑选一个最小的值
for(int i=0;i<=n;i++){
if(vis[i]){//i已经到达过了
la[match[i]]-=delta;//为了让匹配成功降低期望值
ra[i]+=delta;//可以选择的路增多,增加期望值
}
else slack[i]-=delta;//没有被标记,降低期望值更容易匹配
}
y=yy;
if(match[y]==-1)break;//无法进行匹配了
}
while(y){
match[y]=match[pre[y]];
y=pre[y];
}//每一个bfs都能确定一个匹配
}
ll KM()
{
memset(match,-1,sizeof(match));
memset(la,0,sizeof(la));
memset(ra,0,sizeof(ra));
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
bfs(i);
}
ll ans=0;
for(int i=1;i<=n;i++){
ans+=dis[match[i]][i];//负数
}
return -ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
ll x,y,z,v;
for(int i=1;i<=n;i++){
cin>>x>>y>>z>>v;
for(int t=0;t<n;t++){//过了t秒之后i处的位置
dis[t+1][i]=-x*x-y*y-(z+v*t)*(z+v*t);//时间和气球
}
}
cout<<KM();
return 0;
}
K King of Range
题意:
给定一个数组a,有m次查询,问对于每次给定的k,有多少对不同的l,r,在a[l]~a[r]连续的元素内极差是严格大于k
题解:
详情参考 用ST表求得区间a[l,r]里的最大值和最小值,从而得到极差,固定l,移动r,从而来找到一个满足条件的长度,累加起来就可以了
注意:
区间明确,[l,s] [r-(1<<s)+1,s]
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
#define INF 0x3f3f3f3f
typedef long long ll;
int f1[maxn][20],f2[maxn][20],a[maxn], lg[maxn];
int n,m;
void init()
{
for(int i=1;i<=n;i++){
f2[i][0]=f1[i][0]=a[i];
}
for(int i=1;i<=20;i++){
for(int j=1;j+(1<<i)-1<=n;j++){
f1[j][i]=max(f1[j][i-1],f1[j+(1<<(i-1))][i-1]);
f2[j][i]=min(f2[j][i-1],f2[j+(1<<(i-1))][i-1]);
}
}
}
inline int getmin(int l,int r)
{
int s=__lg(r-l+1);
return min(f2[l][s],f2[r-(1<<s)+1][s]);
}
inline int getmax(int l,int r)
{
int s=__lg(r-l+1);
return max(f1[l][s],f1[r-(1<<s)+1][s]);
}
ll solve(int k)
{
ll ans=0;
for(int l=1,r=1;l<=n;l++){
bool flag=(getmax(l,r)-getmin(l,r)>k);
while(!flag&&r<=n){
r++;
if(r==n+1)break;
if(getmax(l,r)-getmin(l,r)>k)flag=true;
}
if(r==n+1)break;//越界离开,到达最远的地方
if(flag)ans+=n-r+1;//包含区间一定会满足
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
init();int k;
for(int i=1;i<=m;i++){
cin>>k;
cout<<solve(k)<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具