牛客练习赛59题解报告

题目链接

A题

题意
给一个字符串
问字符串里有没有出现子序列"XiaoQiao"和“XiaoHuiHui”
题解
用两个字符串存入,并对给定字符串进行On查询

AC代码

#include<bits/stdc++.h>
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=2e5+10;
const ll inf=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    string t="XiaoQiao";
    string s;cin>>s;
    int j=0;
    for(int i=0;i<s.length();i++){
        if(s[i]==t[j])j++;
        if(j==t.length())break;
    }
    if(j<t.length()){cout<<"emm"<<endl;return 0;}
    string tt="XiaoHuiHui";
    j=0;
    for(int i=0;i<s.length();i++){
        if(s[i]==tt[j])j++;
        if(j==tt.length())break;
    }
    if(j<tt.length())cout<<"emm"<<endl;
    else cout<<"Happy"<<endl;
    return 0;
}


B题

题意
在二维平面中给定n个点,每个点有坐标 xi,yi
需要让这n个点连通
第i个点和第j个点建路所需要的花费为
| x x 2i y y i x x 1j y y j + y y 2i( y y i 2 2 x x i ) — y y 2j( y y j 2 2 x x j ) |
问最少需要花费多少
题解
将公式的 i i j j 分离开化简,这里只看 i i

x x 2i y y i + y y 2i ( y y i 2 2 x x i )
由此式子化简可得到
y y i( x x i y y i )2

所以将每个点的值计算出来,排序后让相邻两条建路是最短的
由于 | a a 1 a a 2 + a a 2 a a 3 ············· a a n-1 a a n |
可以推出最后的结果应该是 a a n a a 1

AC代码

#include<bits/stdc++.h>
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=2e5+10;
const ll inf=0x3f3f3f3f;
vector<ll> a;
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++){
        ll x,y;cin>>x>>y;
        a.pb(y*(x-y)*(x-y));
    }
    sort(all(a));
    cout<<*(a.end()-1)-*a.begin()<<endl;
    return 0;
}


C题

题意
x x 件材料 a a        y y 件材料 b b    有两种方法合成装备
2 2 件材料 a a 3 3 件材料 b b 可以合成一套装备
4 4 件材料 a a 1 1 件材料 b b 可以合成一套装备
问最多能合成多少套装备

题解
官方题解用的是三分
我用的方法是贪心,尽量先用 2 2 件材料 a a 3 3 件材料 b b 可以合成一套装备,当材料 a a 和材料 b b 剩余个数是4:1的的时候开始用第二种方法合成装备
设使两个材料之比变成4:1需要用第一种方法合成 n n
x 2 n y 3 n = 4 \frac{x-2n}{y-3n}\quad = 4
化简可以得到
4 y x = 10 n 4y-x=10n
所以可以得到
a n s = { m i n ( x / 4 , y ) , 4 y - x < 0 d + m i n ( x / 4 , y ) , others ans = \begin{cases} min(x/4,y), & \text{4$y$-$x$<$0$} \\ d+min(x/4,y), & \text{others} \end{cases}
(其中 d d 表示化成4:1需要多少次)
d = 4 y x 10 d=\frac{4y-x}{10}\quad
当然可能这个值不会被整除,所以要通过四舍五入判断是应该多算一次第一种情况还是多算一次第二种情况,所以式子变为
d = 4 y x + 5 10 d=\frac{4y-x+5}{10}\quad

AC代码

#include<bits/stdc++.h>
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=2e5+10;
const ll inf=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;cin>>t;
    while(t--){
        ll x,y;
        cin>>x>>y;
        if(4*y<x){cout<<y<<endl;continue;}
        ll d=(4*y-x+5)/10;
        d=min(x/2,d),d=min(y/3,d);
        ll ans=0;
        ans+=d;
        x-=2*d,y-=3*d;
        cout<<ans+min(x/4,y)<<endl;
    }
    return 0;
}


D题

题意
A B A和B 轮流取石子,一共有 n n 个石子, A A 先开始取
假设当前的石子有 k k
k = 1 k=1 的时候B获得胜利
k > = 2 k>=2 的时候将式子分为 f ( k ) f(k) k f ( k ) k-f(k) 两堆,必须取走其中一堆, f ( k ) = x f(k)=x 为满足 x 2 < = k x*2<=k 的最大整数
最后问谁能获得胜利
题解
由于 n n 的范围是 1 e 18 1e18 ,所以不能采取暴力的方法计算
需要打表找规律
如果 A A 上次连续赢的长度为 y y ,可以发现 B B 会连续赢 2 y 1 2*y-1
如果 B B 上次连续赢的长度为 y y ,可以发现 A A 会连续赢 2 y + 1 2*y+1
所以可以使用 O ( l o g   2   n ) O(log~2~n) 的复杂度去找n在谁获胜的区间里

AC代码

#include<bits/stdc++.h>
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=2e5+10;
const ll inf=0x3f3f3f3f;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;cin>>t;
    while(t--){
        ll n;
        cin>>n;
        ll x=1,y=2;
        bool f=1;
        while(x<n){
            if(!f)x+=y,y=2*y+1,f=1;
            else x+=y,y=y*2-1,f=0;
        }
        if(!f)cout<<"XiaoHuiHui"<<endl;
        else cout<<"XiaoQiao"<<endl;
    }
    return 0;
}


E题

题意
一共有 n n 堆石子,每堆有 a i   ai~ 个石子,牛牛要把它们搬走
如果一次搬了 k k 个石子,会对牛牛产生 k 2 k^2 的负担
牛牛最多搬 m m
牛能每次会将第 x x 堆的石子数量变为 v v ,所以每次需要重新计算牛牛的最小负担(总共 q q 次)
题解
由于数据较小
n , k , m , q < = 400 n,k,m,q<=400
可以采用 d p dp 的方法,但是由于石子的数量是改变的,可以通过线段树来优化 d p dp
d p [ i ] [ j ] dp[i][j] 是在线段树的第 i i 个结点,把第 i i 组分隔 j j 次的最小负担 ( j j + 1 ) (分隔j次,总共分出j+1组)

状态转移方程如下:
0 m n 先将叶子结点的0到m-n次分割的最小情况计算出来

广 然后通过转移方程推广到各个非终端结点

d p [ p ] [ i + j ] = m i n ( d p [ i ] [ j ] , d p [ l s o n ] [ i ] + d p [ r s o n ] [ j ] dp[p][i+j]=min(dp[i][j],dp[lson][i]+dp[rson][j]

a n s = d p [ 1 ] [ m n ] 最后ans=dp[1][m-n]

AC代码

#include<bits/stdc++.h>
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=2e5+10;
const ll inf=0x3f3f3f3f;

ll dp[410<<2][410];
int n,m;

void update(int p,int l,int r,int x,ll v){
    if(l==r){
        for(int i=0;i<=m-n;i++){
            ll t=v/(i+1);
            ll a=v%(i+1),b=(i+1)-a;
            dp[p][i]=b*t*t+a*(t+1)*(t+1);
        }
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)update(p<<1,l,mid,x,v);
    else update(p<<1|1,mid+1,r,x,v);
    for(int i=0;i<=m-n;i++)
        dp[p][i]=inf*inf;
    for(int i=0;i<=m-n;i++)
        for(int j=0;i+j<=m-n;j++)
            dp[p][i+j]=min(dp[p][i+j],dp[p<<1][i]+dp[p<<1|1][j]);
}

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>>m;
    for(int i=1,x;i<=n;i++){
        cin>>x;
        update(1,1,n,i,x);
    }
    int q;cin>>q;
    while(q--){
        int x,v;
        cin>>x>>v;
        update(1,1,n,x,v);
        cout<<dp[1][m-n]<<endl;
    }
    return 0;
}

发布了4 篇原创文章 · 获赞 3 · 访问量 1469

猜你喜欢

转载自blog.csdn.net/qq_43756519/article/details/104853746