每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

牛客练习赛109(C,D)

牛客练习赛109(C,D)

C

C

这个题大意是给你一个\(dfs\)序,和每一个点的\(size\),我们需要的答案是这些点的所有边,但是我们还要注意这些边的输出也是有要求的,比如一个边\((u,v)\)必须是\(v>u\),然后这些边是第几个输入的是按照第一个点的大小使得这些\(u\)以单调不减的方式来排序(这个排序我赛时一直没搞明白,真坑,输出就输出,还排什么序呢)

看到这个我第一反应是用\(dfs\)

因为我们都知道\(dfs\)序列好像都是从根节点出发的,那么我们就可以知道出发点了,然后从这个点\(u\)开始遍历,然后对于这个点后面的\(siz[u]-1\)个节点进行遍历,那么对于在这个过程之间相邻的两个点一定是相连的

然后就可以写代码了

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int siz[maxn],dfn[maxn];
int n;
vector<int>g[maxn];
vector<pair<int,int>>ans;
int pos;
int p=0;
bool cmp(pair<int,int> x,pair<int,int> y)
{
    if (x.first!=y.first)
    {
        return x.first<y.first;
    }
    return x.second<y.second;
}
void dfs(int u,int cnt)
{
    while (pos<n&&cnt!=siz[u])
    {
        pos++;
        int v=dfn[pos];
       ans.push_back({min(u,v),max(u,v)});
      //  cout<<min(u,v)<<" "<<max(u,v)<<'\n';//这个好像不好处理那个输出的排序,后面我用了pair才过了的
        cnt+=siz[v];
        if (siz[v]==1) continue;
        dfs(v,1);
    }
    return ;
}
int main ()
{
    ios_base::sync_with_stdio(false);//赛时没加超时了
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin>>n;
   int root=0;
    for (int i=1;i<=n;i++)
    {
       cin>>dfn[i];
    }
    for (int i=1;i<=n;i++)
    {
        cin>>siz[i];
    }
    pos=1;
    dfs(dfn[1],1);
    sort(ans.begin(),ans.end(),cmp);
    for (auto [x,y]:ans)
    {
        cout<<x<<" "<<y<<'\n';
    }
    return 0;
}

D

D

题目大意就是给你\(n\)个数,还有\(m\),你可以进行\(k\)次操作,每进行一次操作,都会选择一个\(i\)\(j\),让\(a_i\)变成\(a_i+m\),\(a_j\)变成\(a_j-m\),而且\(i\)可以等于\(j\),那么就意味着我们可以进行小于等于\(k\)次有效操作,让这\(n\)个数的累乘最大

高中的时候我们学过基本不等式

\[a\times b<=(\frac{a+b}{2})^2 \]

我们两个两个来看,这两个数的和是固定的,我们要想这两个数的和最大,就只能让上面这个不等式成立,而只有\(a==b\)才可以让等于号成立,所以我们可以知道要让和固定两个数的乘积尽量大,只有这两个数的差值尽量小

然后要让这\(k\)个操作发挥到最好的效果,最好是让这些数的两个极端来进行这个操作,那么这\(n\)个数整体也相对于平均了

对于快速求得最大最小值,并且还可能存在相同的数值,我觉得可以用\(multise\)

还有如果只有\(1\)个数的话,不管操作多少次,答案都还是那个值,可以直接输出了

#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int mod=1e9+7;
int n,m,k;
multiset<int>ans;
signed main ()
{
    cin>>n>>m>>k;
    for (int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        ans.insert(x);
    }
    while (k--&&n>1)
    {
        auto x=ans.begin();
        auto y=ans.end();
        y--;
        int t=*x;
        int tt=*y;
        int a=t+m;
        int b=tt-m;
        if (tt-t<m) break;//使两个数之间的差值变小,只有这两个数原来的差值大于m
        //如 m=5  5和9可以变成10 4差值变成6了,那么就会使答案变小,
        //如 5  11 可以变成10 6 差值有原来的6变成4,可以是答案变小
        //为什么这些数差值更小累乘就更小
        //可以想想基本不等式
        ans.erase(x);
        ans.erase(y);
        ans.insert(a);
        ans.insert(b);
    }
  
    int sum=1;
    for (auto x:ans)
    {
        sum=(sum*x)%mod;
    }
    cout<<sum<<'\n';
    return 0;
}
posted @ 2023-03-03 13:53  righting  阅读(51)  评论(0)    收藏  举报