2021年牛客暑期多校训练营5

2021年牛客暑期多校训练营5

A Away from College(待)

题意:

题解:

注意:

代码:

B Boxes

题意:

已知有n个箱子,每个箱子里面装的可能是白球也可能是黑球,现在可以让你打开箱子看一看,每个箱子i打开都需要w[i]的费用,也可以获得一个提示,得知之后的黑球个数,需要费用C,现在求最小的费用是多少

题解:

我们可以考虑先把盒子打开,当然费用当然是从小到大算起,求一个前缀和,w[i]表示的就是打开了i个盒子一共所需要的费用。之后再索要提示,只要剩下的n-i个小球如果全是黑球那么就猜测成功,概率就是p=2ni​所以期望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个字母有 i=0min(x,y)CxiCyi​​
i=0xCxxiCyi=CxxCy0+Cxx1Cy1++Cx0Cyx​​​ (假设x<y)
二项式定理 (1+a)x=Cx0a0+Cx1a1++Cxxax,(1+a)y=Cy0a0+Cy1a1++Cyyay​​​
(1+a)x(1+a)y=i=0x+yj=0iCxjCyijai=(1+a)x+y​​​ 也就是说ax​​​的系数就是我们想要求的组合数
i=0xCxxiCyi=CxxCy0+Cxx1Cy1++Cx0Cyx=Cx+yx​​​
这里用上一个乘法逆元即可 abmodp=ainv(b)modp​​​
费马小定理apamodp​​​ 则 ap2a1modp​​​ 那么可以用ap2​​​来代替a1​​​作为a的逆元 即inv(a)=ap2%p​​
我们可以通过快速幂来求inv(n!)​​​ 再进行线性递推得到其他阶乘的逆元 inv((n1)!)modp=ninv(n!)modp​​​​​​​​​​​​​​​​ 
证明如下:

n!inv(n!)1modp(n1)!inv((n1)!)1modpn!inv((n1)!)nmodpn!inv(n!)inv((n1)!)ninv(n!)modpinv((n1)!)ninv(n!)modp​​​​

注意:

当前缀为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;
}
posted @   Aaryn21  阅读(55)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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生成工具
点击右上角即可分享
微信分享提示