2021.3.28 字节跳动笔试 - 第四场

比昨天米哈游简单得多,一共四道题
虽然字节不给用本地IDE吧,但是其实牛客的IDE也还行(?)
前两题DP,第三题二分,最后一题组合数学。

一、 今天有 n n n 个会议,每个会议有一个起始时间 L L L 和一个终止时间 R R R ,参加一个会议就必须要从头参加到底,不能中途参加别的会议。问今天最多能参加多少个会议。( n ≤ 100 n \le 100 n100 0 ≤ L ≤ 24 0 \le L \le 24 0L24

思路: 巧了,这就跟我校赛出的题的思路一样,而且简单得多。
当时那题的题解:
在这里插入图片描述
因为会议数很少,只有100,所以对每个会议的终止时间进行DP即可。
DP公式:

//dp[i]表示时间i前能参加的最大会议数
dp[i]=dp[i-1];
if(i==a[i].ed) dp[i]=max(dp[a[i].st]+1,dp[i]); //如果当前时间是一个会议结束时间,那么进行dp

AC参考代码:

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int maxn=1e3+10;
const int mod=1e9+7;

struct node {
    
    
    int st;
    int ed;
}a[maxn];

bool cmp(node x,node y) {
    
    
    return x.st<y.st;
}

int dp[maxn];

int main() {
    
    
    ios::sync_with_stdio(false);
    cin.tie(0),cin.tie(0);
    int n;
    cin>>n;
    for(int i=0;i<n;i++) {
    
    
        cin>>a[i].st>>a[i].ed;
    }
    sort(a,a+n,cmp);
    for(int i=1;i<=24;i++) {
    
    
        dp[i]=dp[i-1];
        for(int j=0;j<n;j++) {
    
    
            if(i==a[j].ed) dp[i]=max(dp[a[j].st]+1,dp[i]);
        }
    }
    cout<<dp[24]<<endl;
}

二、 有一个寿司转盘,其中有许多寿司,每个寿司有它的价值,你吃了其中一个寿司之后就不能吃它相邻的寿司了,问能吃到的寿司的价值之和的最大值。(第一个与第 n n n 个不相邻, n ≤ 1 0 3 n \le 10^3 n103
比如 9 4 2 3,那么吃 9 和 3 就是价值和最大。

思路:
没给输入 n n n,是循环输入, while(cin>>val[j++]);
d p [ 0 ] [ i ] dp[0][i] dp[0][i] 表示不吃第i个寿司能获得的最大价值和
d p [ 1 ] [ i ] dp[1][i] dp[1][i] 表示吃第i个寿司能获得的最大价值和
所以DP公式:

dp[0][i]=dp[1][i-1];
dp[1][i]=max(dp[0][i-1]+val[i],dp[1][i-1]);

AC参考代码:

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int maxn=1e3+10;
const int mod=1e9+7;

int dp[2][maxn];
int val[maxn];

int main() {
    
    
    ios::sync_with_stdio(false);
    cin.tie(0),cin.tie(0);
    int j=1;
    while(cin>>val[j++]);
    for(int i=1;i<j;i++) {
    
    
        dp[0][i]=dp[1][i-1];
        dp[1][i]=max(dp[0][i-1]+val[i],dp[1][i-1]);
    }
    cout<<max(dp[1][j-1],dp[0][j-1])<<endl;
    return 0;
}

三、 n n n 条边,给出每条边的值。给出三角形优雅值的定义: a , b , c a,b,c abc 为三角形三条边,则这个三角形的优雅值为: ∣ a − b ∣ + ∣ a − c ∣ + ∣ b − c ∣ |a-b|+|a-c|+|b-c| ab+ac+bc ,且等腰三角形优雅值为 0 0 0
问这 n n n 条边能组成的三角形的优雅值最大是多少,如果不能组成三角形则输出 0 0 0。( n ≤ 1 0 5 n \le 10^5 n105,边长在 32 32 32 位整形范围以内)

样例:

5
2 3 4 9 11

输出:

5

思路: 时间复杂度必须是 O ( n l o g n ) O(nlogn) O(nlogn) 以内,那么就只能二分。
因为不能有等腰三角形,所以先去重,然后再排序。
令第一条边等于 v a l [ 0 ] val[0] val[0],第二条边 i i i 枚举从 n − 1 n-1 n1 1 1 1,二分查找这两条边的和作为第三条边,如果找到的 p o s pos pos 等于 0 0 0 就加 1 1 1,如果等于 i i i 就加 1 1 1 或减 1 1 1
令第一条边等于 v a l [ n − 1 ] val[n-1] val[n1],第二条边 i i i 枚举 1 1 1 n − 2 n-2 n2,二分查找这两条边的和作为第三条边,如果找到的 p o s pos pos 等于 n − 1 n-1 n1 就减 1 1 1,如果等于 i i i 就加 1 1 1 或减 1 1 1
取这里面找到的三角形的优雅值的最大值。

AC参考代码:

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int maxn=1e3+10;
const int mod=1e9+7;

vector<ll>val;
map<ll,bool>mp;

bool is_tri(ll a,ll b,ll c) {
    
    
    if(a+b>c&&b+c>a&&a+c>b) return 1;
    return 0;
}

int main() {
    
    
    ios::sync_with_stdio(false);
    cin.tie(0),cin.tie(0);
    int n;
    cin>>n;
    for(int i=0;i<n;i++) {
    
    
        ll x; cin>>x;
        if(!mp[x]) val.emplace_back(x);
        mp[x]=1;
    }
    sort(val.begin(),val.end());
    ll ans=0;
    ll a=val[0];
    for(int i=n-1;i>=1;i--) {
    
    
        ll b=val[i];
        int pos=lower_bound(val.begin(),val.end(),a+b)-val.begin()-1;
        if(pos==0) pos++;
        if(pos==i) pos--;
        if(pos>=0&&pos<n&&pos!=0&&pos!=i) {
    
    
            if(is_tri(val[pos],a,b)) {
    
    
                ll tmp=abs(a-b)+abs(a-val[pos])+abs(b-val[pos]);
                ans=max(ans,tmp);
            }
        }
        pos=i+1;
        if(pos>=0&&pos<n&&pos!=0&&pos!=i) {
    
    
            if(is_tri(val[pos],a,b)) {
    
    
                ll tmp=abs(a-b)+abs(a-val[pos])+abs(b-val[pos]);
                ans=max(ans,tmp);
            }
        }
    }
    a=val[n-1];
    for(int i=0;i<n-1;i++) {
    
    
        ll b=val[i];
        int pos=lower_bound(val.begin(),val.end(),a+b)-val.begin()-1;
        if(pos==n-1) pos--;
        if(pos==i) pos++;
        if(pos>=0&&pos<n&&pos!=n-1&&pos!=i) {
    
    
            if(is_tri(val[pos],a,b)) {
    
    
                ll tmp=abs(a-b)+abs(a-val[pos])+abs(b-val[pos]);
                ans=max(ans,tmp);
            }
        }
        pos=i-1;
        if(pos>=0&&pos<n&&pos!=n-1&&pos!=i) {
    
    
            if(is_tri(val[pos],a,b)) {
    
    
                ll tmp=abs(a-b)+abs(a-val[pos])+abs(b-val[pos]);
                ans=max(ans,tmp);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

四、 有一个 n ∗ m n*m nm 大小的迷宫,有 q q q 个障碍,只能向上或者向右走,问从点 ( 1 , 1 ) (1,1) (1,1) 到点 ( n , m ) (n,m) (n,m) 的方案数。( 1 ≤ n , m ≤ 1 0 5 1 \le n,m \le 10^5 1n,m105 q ≤ 15 q \le 15 q15

思路: 以为是图论搜索,想了想,太大了,不会。本来想着混点分,结果 dfs 跟 bfs 都是 0% 通过率。麻了。当时有想着用 DP 的,但是急了,没写,好 jb 亏,心态有点崩

结束之后, q h qh qh 突然想到了,用所有的方案数减去经过障碍的方案数。。。woc,突然就简单了起来。因为障碍数只有 15 15 15 个,且只能走 2 2 2 个方向,所以最多也就 2 15 2^{15} 215 。。真的心态大蹦 T_T 。

猜你喜欢

转载自blog.csdn.net/weixin_44012745/article/details/115287488