首页 > 其他分享 >牛客周赛 Round 71

牛客周赛 Round 71

时间:2024-12-11 21:09:46浏览次数:3  
标签:int ll sum 牛客 maxn 71 ans Round dp

题解

A

x+y=n,共可以构造n-1对(x,y),题目询问是否能构造k对,比较大小即可

B

摘一定数量的宝石,使手环破裂,贪心最近的相同宝石,暴力的思路,先选取一个宝石,找下一个相同的宝石,记录相邻的最小值,时间复杂度
\(O(n^2)\)
优化:我们将相同的宝石放在一起,记录他们在手环中的位置,这样每次遍历,每个宝石只会被枚举一次,统计时,每个宝石也只会被统计一次

注意:统计最后一个宝石的时候,由于是环,应该计算与第一个宝石的距离

#include<bits/stdc++.h>

using namespace std;
int n;
const int maxn=2e5+10;
char m[maxn];
vector<int>a[29];

int t;
int main(){
    cin>>t;
    while(t--){
        for(int i=0;i<29;++i)a[i].clear();
        cin>>n;
        for(int i=1;i<=n;++i){
            char c;c=getchar();if(c=='\n') c=getchar();
            a[c-'a'].push_back(i);//统计相同宝石的位置
        }
        int ans=1e9+10;
        for(int i=0;i<26;++i){//枚举每个宝石
            int len=a[i].size();
            if(len<=1) continue;
            ans=min(ans,n-a[i][len-1]+a[i][0]-1);
            for(int j=1;j<len;++j){
                ans=min(ans,a[i][j]-a[i][j-1]-1);//记录最小距离
            }
        }
        if(ans==1e9+10) puts("-1");
        else cout<<ans<<endl;
    }
    return 0;
}


C

一个不难的思维题
\(\\\)
可以任意插入,这里操作空间就很大了
\(\\\)
我们思考一件事,在给定的字符串中插入后,会生成由若干个循环节组成的字符串,这个循环节应该满足什么条件,他应该包含原来字符串所有过的全部字母

否则我们我们循环节如何构造,组成的字符串都无法由原来的字符串插入形成

而对于每一个原来字符串中含有的字符,都可以插入任意字符组成循环节,而刚好包含所有已知字符的循环节最小

例子:
bhdsd

bhds bhds bhds bhds bhds


#include<bits/stdc++.h>

using namespace std;
string s;
map<int,int> mp;
int main(){
    cin>>s;
    int ans=0;
    for(int i=0;i<s.length();++i)
        if(mp[s[i]]==0) ++ans,mp[s[i]]=1;
    cout<<ans<<endl;
    return 0;
}

D

两种做法,前缀和,dp

思考

答案最后组成序列,我们是可以知道一些信息的,

  • 最后一定是三段,
  • 三段一定是\(0,1,2\)的某种排列

前缀和

前缀和的这个做法比较典型,而且优化也是典型,可以重点记忆学习

很自然的我们想到,枚举三个区间的中间的两个分割点,统计每一段染色的时间,求最小值即可

暴力是O(n3),用前缀和是O(n2)

着重讲最后这个优化
前缀和时会有两个指针,j,i(j<i),同时枚举两个指针,会是复杂度增加,这里就有典型的优化方式
枚举i的时候j已经被枚举过了,我们只需要记录下来使值最小的j就行

设\(a_0,a_1,a_2\)是0,1,2的某种排列,分别代表三段的颜色

sumt[i][j]表示前j个所有气球变为i所需时间

\(ans=min(ans,sum[a_0][i]+sum[a_1][j]-sum[a_1][i]+sum[a_2][n]-sum[a_2][j]\)

这时我们发现这个表达式中sum[a_0][i]和sum[a_1][i]都是以i下标为结尾,可以用pre[i]先统计一遍,再枚举一遍j时间复杂度就降到了O(n)


#include<bits/stdc++.h>


using namespace std;
#define ll long long
const int maxn=2e5+10;
ll sumt[5][maxn];
ll pre[maxn];
int t[maxn];
int n;
int a[3]={0,1,2};

void solve(){
    string s;cin>>s;
    for(int i=1;i<=n;++i) cin>>t[i];
    for(int i=1;i<=n;++i){
        sumt[0][i]=sumt[0][i-1];
        sumt[1][i]=sumt[1][i-1];
        sumt[2][i]=sumt[2][i-1];
        if(s[i-1]=='0') sumt[1][i]+=t[i],sumt[2][i]+=t[i];
        else if(s[i-1]=='1') sumt[0][i]+=t[i],sumt[2][i]+=t[i];
        else if(s[i-1]=='2') sumt[0][i]+=t[i],sumt[1][i]+=t[i];
    }
    ll ans=1e15;
    do{
        pre[1]=sumt[a[0]][1]-sumt[a[1]][1];
        for(int i=2;i<=n;++i) 
            pre[i]=min(pre[i-1],sumt[a[0]][i]-sumt[a[1]][i]);
        for(int i=n+1;i>=1;--i) 
            ans=min(ans,sumt[a[2]][n]-sumt[a[2]][i-1]+sumt[a[1]][i-1]+pre[i-1]);
    
    }while(next_permutation(a,a+3));
    cout<<ans<<endl;
}
int main(){
    cin>>n;
    solve();
    return 0;
}

DP

这里dp的思路类似于逆向的dfs

dfs搜索
我们考虑当前 2,那前面可以是0,1,2
是1的话,前面可以是0,1

\(dfs(i)=dfs(i-1)+t[i] 如果颜色不同\)
\(dfs(i)=dfs(i-1)\)

但是直接的dfs会超时
此时用dp,状态转移一遍就可以了

#include<bits/stdc++.h>

using namespace std;
#define ll long long 
int n;
const int maxn=2e5+10;
int a[8]={0,1,2};
string s;
ll t[maxn];
ll ans=1e18;ll dp[4][maxn];
void solve(){
    
    do{    
        memset(dp,0x3f3f3f3f3f3f3f,sizeof(dp));
        dp[0][0]=dp[1][0]=dp[2][0]=0;
        for(int i=1;i<=n;++i){
            for(int j=0;j<3;++j)
                for(int k=0;k<=j;++k)
                    dp[a[j]][i]=min(dp[a[j]][i],dp[a[k]][i-1]+(a[j]!=s[i-1]-'0')*t[i-1]);
        } 
        for(int i=0;i<3;++i) ans=min(ans,dp[i][n]);
    }while(next_permutation(a,a+3));
    
}
int main(){
    cin>>n;
    cin>>s;for(int i=0;i<n;++i) cin>>t[i];
    solve();
    cout<<ans<<endl;
    return 0;
}

E

纯模拟了,暴力不超时
貌似数据不够好,只用最长有两个等边就可以

#include<bits/stdc++.h>

using namespace std;
#define int long long 
int n;
const int maxn=1e6+10;
int t;

map<int,int>mp;
signed  main(){
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);double ans=0;
        int l=0;mp.clear();
        for(int i=1;i<=n;++i){
            int x,y;
            scanf("%lld %lld",&x,&y);
            mp[x]+=y;
            if(mp[x]>=2 && x>l) l=x;//记录最大的等腰边
        }
        for(auto [x,y]:mp){
            if(x==l && y<=2) continue;
            if(x>=2*l) continue;
            double p=(x+l*2)*1.0/2;//海伦公式计算
            ans=max(ans,(double)sqrt(p*(p-l)*(p-l)*(p-x)));
        }
        if(ans==0) puts("-1");
        else printf("%.10lf\n",ans);
    }

}

标签:int,ll,sum,牛客,maxn,71,ans,Round,dp
From: https://www.cnblogs.com/guiyou/p/18600332

相关文章

  • Goby AI 2.0 自动化编写 EXP | Mitel MiCollab 企业协作平台 npm-pwg 任意文件读取漏
    漏洞名称:MitelMiCollab企业协作平台npm-pwg任意文件读取漏洞(CVE-2024-41713)EnglishName:MitelMiCollab/npm-pwgFileReadVulnerability(CVE-2024-41713)CVSScore:6.8漏洞描述:MitelMiCollab是加拿大Mitel公司推出的一款企业级协作平台。该漏洞存在于MiCollab......
  • 2717. 半有序排列
    给你一个下标从0开始、长度为n的整数排列nums。如果排列的第一个数字等于1且最后一个数字等于n,则称其为半有序排列。你可以执行多次下述操作,直到将nums变成一个半有序排列:选择nums中相邻的两个元素,然后交换它们。返回使nums变成半有序排列所需的最小操作......
  • LeetCode:2717、半有序队列
    题目:给你一个下标从0开始、长度为n的整数排列nums。如果排列的第一个数字等于1且最后一个数字等于n,则称其为半有序排列。你可以执行多次下述操作,直到将nums变成一个半有序排列:选择nums中相邻的两个元素,然后交换它们。返回使nums变成半有序排列所需的最......
  • 代码随想录算法训练营第四十三天|LeetCode300.最长递增子序列、LeetCode674.最长连续
    前言打卡代码随想录算法训练营第49期第四十三天 (๑ˉ∀ˉ๑)首先十分推荐学算法的同学可以先了解一下代码随想录,可以在B站卡哥B站账号、代码随想录官方网站代码随想录了解,卡哥清晰易懂的算法教学让我直接果断关注,也十分有缘和第49期的训练营大家庭一起进步。LeetCode300......
  • Codeforces Round 992 (Div. 2) A~D
    目录A思路代码B思路代码C思路代码D解法\(1\)思路代码解法\(2\)思路代码解法\(3\)思路代码广告:starrycoding\(9\)折优惠码:FV7B04LL\(E\)有空再补构造场,构造低手掉分.A不记得为什么卡了,居然写了\(7\min\).思路\(n\le10^2\),甚至可以使用\(n^3\)算法.枚......
  • Google Kickstart2022 Round H Problem B 魔法百合井
    很好的一道dp题传送门思考通过几次尝试,你会发现贪心貌似不可用贪心的思路,只统计目前已有的百合花,然后相加,你会发现,会留下一定数量的百合花,小于统计值,只能一个一个加,反而导致总硬币更多尝试dp怎么得到答案设f[x]是得到x朵花的最小硬币数我们先不考虑f[x]怎么得到考虑怎......
  • CodeTON Round 9 D.Shohag Loves GCD
    思路(贪心+唯一分解定理)这个题其实只需要考虑一件事:记答案数组为\(a\),对于两个不同下标\(i\)和\(j\),当\(\gcd(i,j)=\min(i,j)\)时,我们只需要让\(a_{\max(i,j)}<a_{\min(i,j)}\)即可。证明:任意两个数\(x,y\),一定有\(\gcd(x,y)\leq\min(x,y)\)。第一种情况,如果......
  • ybt1671
    1671:扑克牌时间限制:1000ms内存限制:262144KB【题目描述】一副扑克牌有\(n\)张牌。一般你买的一副新扑克牌里除了这\(n\)张牌外还会有一些张特殊的牌,如果你不小心弄丢了\(n\)张牌中的某一张,就可以用特殊牌来代替,但是如果你弄丢两张的话就没有办法了,因为特殊牌上的......
  • (牛客网2024最新版)1100+大厂面试题附答案详解
    Java现在好找工作吗?目前还是挺好找的,楼主我是java开发将近10年了,做架构师也有两三年了,我发现只要是水平高的基本上能找到好工作,就算这两年形势这么差,也还是能找到好工作的,那么我就来说说java方面要达到一个什么样的水平才能找到好工作吧。java方面什么jdk源码就不......
  • 牛客小白月赛106
    牛客小白月赛106比赛链接:牛客小白月赛106//也就写写水题骗自己了A.最后DISCO直接秒,注意一下c可以等于0#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineinfINT32_MAX#definePIIpair<int,int>#defineendl'\n'inlinevoidsolve(){......