牛客练习赛63题解

题目链接

A. 牛牛的三角形

题意:
给 n 条 边 , 是 否 能 找 到 三 条 边 组 成 一 个 三 角 形 给n条边,是否能找到三条边组成一个三角形 n
题解:
n < = 1 e 2 n<=1e2 n<=1e2
由 于 n 很 小 , 直 接 暴 力 枚 举 边 即 可 由于n很小,直接暴力枚举边即可 n
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int a[110];


int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++){
                if(i==k||i==j||k==j)continue;
                if(a[i]+a[j]>a[k]&&a[i]+a[k]>a[j]&&a[k]+a[j]>a[i]){
                    cout<<a[i]<<' '<<a[j]<<' '<<a[k]<<endl;
                    return 0;
                }
            }
    cout<<"No solution"<<endl;
    return 0;
}



B. 牛牛的鱼缸

题意:
给 一 个 宽 l 高 h 的 鱼 缸 给一个宽l高h的鱼缸 lh
把 他 放 在 一 个 底 边 为 L , 高 为 H 的 斜 劈 上 , 看 能 装 多 少 水 把他放在一个底边为L,高为H的斜劈上,看能装多少水 LH
题解:
首 先 需 要 分 类 讨 论 首先需要分类讨论
看 这 个 鱼 缸 高 度 够 不 够 高 使 得 水 的 形 状 是 梯 形 看这个鱼缸高度够不够高使得水的形状是梯形 使
如 果 不 够 , 那 么 则 是 一 个 三 角 形 如果不够,那么则是一个三角形
平 行 内 错 角 相 等 , 形 成 三 角 形 右 边 的 角 和 斜 劈 的 角 是 相 等 的 平行内错角相等,形成三角形右边的角和斜劈的角是相等的
三 角 形 的 情 况 说 明 鱼 缸 的 左 臂 一 定 是 全 部 覆 盖 了 , 所 以 三 角 形 的 高 是 h , 但 低 端 不 一 定 全 部 覆 盖 , 要 根 据 鱼 缸 高 度 来 看 三角形的情况说明鱼缸的左臂一定是全部覆盖了,所以三角形的高是h,但低端不一定全部覆盖,要根据鱼缸高度来看 h
已 知 h 和 角 度 又 是 直 角 三 角 形 , 算 一 下 底 边 即 可 知 道 面 积 已知h和角度又是直角三角形,算一下底边即可知道面积 h
然 后 说 梯 形 的 情 况 , 想 象 一 下 梯 形 的 情 况 然后说梯形的情况,想象一下梯形的情况
鱼 缸 左 臂 覆 盖 , 右 臂 覆 盖 一 部 分 , 低 端 全 部 覆 盖 鱼缸左臂覆盖,右臂覆盖一部分,低端全部覆盖
所 以 很 容 易 知 道 , 提 醒 下 底 是 h , 高 是 l , 只 要 找 到 上 底 就 行 了 所以很容易知道,提醒下底是h,高是l,只要找到上底就行了 hl
这 个 梯 形 可 以 分 成 一 个 三 角 形 和 一 个 平 行 四 边 形 这个梯形可以分成一个三角形和一个平行四边形
整 个 鱼 缸 的 上 部 缺 了 一 个 和 这 个 三 角 形 完 全 一 样 的 三 角 形 就 能 填 满 整个鱼缸的上部缺了一个和这个三角形完全一样的三角形就能填满
所 以 梯 形 少 了 三 角 形 的 一 个 底 , 这 个 三 角 形 的 高 l 和 角 度 仍 然 是 确 定 的 , 算 底 即 可 所以梯形少了三角形的一个底,这个三角形的高l和角度仍然是确定的,算底即可 l
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};



int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    double h,l,H,L;
    cin>>h>>l>>H>>L;
    double x=H/L;
    if(x>=h/l)
        printf("%.9lf",h*h/x/2);
    else{
        double ans=(h-l*x+h)*l/2;
        printf("%.9lf",ans);
    }
    return 0;
}



C. 牛牛的揠苗助长

题意:
n 块 菜 地 , 每 块 高 度 为 a i n块菜地,每块高度为a_i nai
第 一 天 a 1 + 1 , 第 二 天 a 2 + 1 , 第 n 天 a 3 + 1 第一天a_1+1,第二天a_2+1,第n天a_3+1 a1+1,a2+1,na3+1
第 n + 1 天 a 1 + 1 , 一 次 类 推 第n+1天a_1+1,一次类推 n+1a1+1
每 一 天 可 以 使 得 每 一 块 地 的 高 度 加 一 或 者 减 一 每一天可以使得每一块地的高度加一或者减一 使
问 最 少 多 少 天 可 以 使 每 块 地 高 度 一 样 问最少多少天可以使每块地高度一样 使
题解:
这 道 题 大 致 一 看 , 感 觉 是 要 二 分 答 案 来 写 这道题大致一看,感觉是要二分答案来写
然 后 思 考 一 下 二 分 答 案 的 可 行 性 然后思考一下二分答案的可行性
如 果 x 是 最 后 的 结 果 , 那 么 x + 1 那 一 天 增 高 的 高 度 如果x是最后的结果,那么x+1那一天增高的高度 xx+1
可 以 减 一 去 掉 , 这 样 就 等 于 这 天 什 么 都 没 发 生 可以减一去掉,这样就等于这天什么都没发生
这 样 就 可 以 看 出 , 即 使 天 数 超 过 结 果 , 最 后 也 是 可 以 达 到 目 的 这样就可以看出,即使天数超过结果,最后也是可以达到目的 使
确 定 了 算 法 之 后 , 就 要 写 每 次 答 案 的 判 断 函 数 确定了算法之后,就要写每次答案的判断函数
首 先 把 每 块 地 x 天 之 后 的 高 度 列 出 , 此 时 你 有 x 次 可 以 使 一 块 地 加 减 一 首先把每块地x天之后的高度列出,此时你有x次可以使一块地加减一 xx使
假 设 你 使 得 所 有 地 成 为 h 高 度 需 要 的 次 数 是 r e s 假设你使得所有地成为h高度需要的次数是res 使hres
原 本 有 a 块 地 小 于 h , b 块 地 大 于 h 原本有a块地小于h,b块地大于h ahbh
那 么 使 得 所 有 地 成 为 h − 1 的 次 数 是 r e s + a − b 那么使得所有地成为h-1的次数是res+a-b 使h1res+ab
通 过 这 个 可 以 得 出 如 果 只 有 当 a > = b 时 h 的 最 小 值 通过这个可以得出如果只有当a>=b时h的最小值 a>=bh
那 么 就 是 排 序 后 取 得 第 ( n + 1 ) / 2 小 的 高 度 那么就是排序后取得第(n+1)/2小的高度 (n+1)/2
然 后 每 块 地 看 到 这 个 高 度 需 要 多 少 次 , 如 果 次 数 大 于 x 则 不 成 立 然后每块地看到这个高度需要多少次,如果次数大于x则不成立 x
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int n;
ll a[maxn],b[maxn];
bool ok(ll x){
    for(int i=1;i<=n;i++){
        b[i]=a[i]+x/n;
        if(x%n>=i)b[i]++;
    }
    sort(b+1,b+1+n);
    ll y=b[(n+1)/2],res=0;
    for(int i=1;i<=n;i++)res+=abs(y-b[i]);
    return x>=res;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    ll l=0,r=1e18,ans;
    while(l<=r){
        ll mid=l+r>>1;
        if(ok(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    cout<<ans;
    return 0;
}



D. 牛牛的01限定串

题意:
给 定 两 个 01 字 符 串 s , t 给定两个01字符串s,t 01s,t
如 果 某 个 字 符 串 的 每 个 字 符 个 数 等 于 另 一 个 字 符 串 的 每 个 字 符 个 数 如果某个字符串的每个字符个数等于另一个字符串的每个字符个数
那 么 这 两 个 字 符 串 相 似 那么这两个字符串相似
字 符 串 t 有 0 , 1 , ? ( 即 不 确 定 ) 字符串t有0,1,?(即不确定) t0,1,?
如 果 s , t 每 有 一 个 前 缀 相 似 , 结 果 加 v a l p r e 如果s,t每有一个前缀相似,结果加val_{pre} s,tvalpre
如 果 s , t 每 有 一 个 后 缀 相 似 , 结 果 加 v a l s u f 如果s,t每有一个后缀相似,结果加val_{suf} s,tvalsuf
字 符 串 t 中 总 共 有 c n t 1 个 1 和 c n t 0 个 0 字符串t中总共有cnt_1个1和cnt_0个0 tcnt11cnt00
问 最 小 结 果 和 最 大 结 果 分 别 是 多 少 问最小结果和最大结果分别是多少
题解:
n < = 1 e 3 n<=1e3 n<=1e3
范 围 不 是 很 大 , 所 以 可 以 考 虑 二 维 d p 范围不是很大,所以可以考虑二维dp dp
d p 1 [ i ] [ j ] 表 示 前 i 个 数 里 有 j 个 1 时 候 的 最 小 结 果 , d p 2 [ i ] [ j ] 为 最 大 结 果 dp1[i][j]表示前i个数里有j个1时候的最小结果,dp2[i][j]为最大结果 dp1[i][j]ij1dp2[i][j]
然 后 用 一 个 前 缀 和 将 s 前 i 位 有 多 少 个 1 维 护 一 下 然后用一个前缀和将s前i位有多少个1维护一下 si1
如 果 j 等 于 此 时 s 的 前 缀 1 了 , 那 么 结 果 加 v a l p r e 如果j等于此时s的前缀1了,那么结果加val_{pre} js1valpre
如 果 c n t 1 − j 等 于 此 时 s 的 后 缀 1 , 加 过 加 v a l s u f 如果cnt_1-j等于此时s的后缀1,加过加val_{suf} cnt1js1valsuf
然 后 对 第 i 位 为 0 和 为 1 进 行 分 情 况 即 可 然后对第i位为0和为1进行分情况即可 i01
但 由 于 字 符 串 t 的 一 部 分 已 经 给 出 , 所 以 要 确 保 字 符 串 可 以 等 于 0 或 1 但由于字符串t的一部分已经给出,所以要确保字符串可以等于0或1 t01
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

ll dp1[1010][1010],dp2[1010][1010];
int sum[1010];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,c0,c1,vp,vs;
    cin>>n>>c0>>c1>>vp>>vs;
    string s,t;
    cin>>s>>t;
    s='.'+s,t='.'+t;
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1];
        if(s[i]=='1')sum[i]++;
    }
    for(int i=0;i<=n;i++)
        for(int j=0;j<=c1;j++)
            dp1[i][j]=1e18,dp2[i][j]=-1e18;
    dp1[0][0]=dp2[0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=c1;j++){
            ll tmp;
            if(t[i]!='1'){
                tmp=dp1[i-1][j];
                if(j==sum[i])tmp+=vp;
                if(sum[n]-sum[i-1]==c1-j)tmp+=vs;
                dp1[i][j]=min(dp1[i][j],tmp);
                tmp=dp2[i-1][j];
                if(j==sum[i])tmp+=vp;
                if(sum[n]-sum[i-1]==c1-j)tmp+=vs;
                dp2[i][j]=max(dp2[i][j],tmp);
            }
            if(t[i]!='0'&&j-1>=0){
                tmp=dp1[i-1][j-1];
                if(j==sum[i])tmp+=vp;
                if(sum[n]-sum[i-1]==c1-j+1)tmp+=vs;
                dp1[i][j]=min(dp1[i][j],tmp);
                tmp=dp2[i-1][j-1];
                if(j==sum[i])tmp+=vp;
                if(sum[n]-sum[i-1]==c1-j+1)tmp+=vs;
                dp2[i][j]=max(dp2[i][j],tmp);
            }
        }
    cout<<dp1[n][c1]<<' '<<dp2[n][c1];
    return 0;
}


你可能感兴趣的:(牛客练习赛63题解)