牛客周赛 Round 90【题解完成】

123 阅读4分钟
题目难度知识点
A 真爱粉Tk(一)签到
B 真爱粉Tk(二)签到
C Tk的构造数组贪心
D 真爱粉Tk(三)★★二分
E Tk的染色树贪心/思维
F Tk的排列间异或★★构造

image.png

总体感觉不难题目挺有趣的,但是自己打红温了。A题秒wa 后来发现想歪了,影响不大改了过了。B题想了个贪心的做法各种搞发现想歪了,调了很久,看了C过人了看了一下有思路过了,接着调B后来发现直接前后指针就行。心态崩了一大半调了好久,看D有思路调了很久一直没过(此类型的题今天刚做),此时彻底心态崩了想下机了,看了F有思路写wa煎熬,E题脑子宕机随机骗了点分。然后一直调D一直没过,最后10几分钟看了看F发现了正确构造方法过了,D题还是没过(构造的例子都能过就是不过),E题不想看了。最后4题下机。

真爱粉Tk(一)

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
int main(void)
{
    LL x; cin>>x;
    if((x*10)%25==0) puts("Yes");
    else puts("No");
    return 0;
}

由于输入的是整数

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
int a[N],t,n;
int main(void)
{
    int n; cin>>n;
    if(n%5==0) puts("Yes");
    else puts("No");
    return 0;
}

真爱粉Tk(二)

从最终状态推,一定5再前2在后,那么就看最终状态5的位置中现在有多少个2。这个就是答案。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
int main(void)
{
    int n; cin>>n;
    string s; cin>>s;
    int cnt2=0,cnt5=0;
    for(int i=0;i<n;i++) 
        if(s[i]=='5') cnt5++;
    for(int i=0;i<cnt5;i++)
        if(s[i]=='2') cnt2++;
    cout<<cnt2;
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
int a[N],t,n;
int main(void)
{
    int n; cin>>n;
    string s; cin>>s;
    int ans=0;
    int i=-1,j=n;
    while(i<j)
    {
        do i++;while(s[i]=='5');
        do j--;while(s[j]=='2');
        if(i<j) swap(s[i],s[j]),ans++;
    }
    cout<<ans;
    return 0;
}

Tk的构造数组

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],b[N],ans[N],n;
int main(void)
{
    int n; cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    vector< pair<LL,int> >ve1,ve2;
    for(int i=1;i<=n;i++)
    {
        ve1.push_back({a[i]*i,i});
        ve2.push_back({b[i],i});
    }
    sort(ve1.begin(),ve1.end());
    sort(ve2.begin(),ve2.end());
    map<int,int>mp;
    for(int i=0;i<n;i++) 
    {
        mp[ve1[i].second]=ve2[i].second;
    }
    for(int i=1;i<=n;i++) cout<<b[mp[i]]<<" ";
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],s[N],b[N],n,ans[N];
int main(void)
{
    int n; cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],s[i]=i*a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    priority_queue< pair<LL,int> >q,q1; 
    for(int i=1;i<=n;i++)
    {
        q.push({s[i],i});
        q1.push({b[i],i});
    }
    while(q.size())
    {
        auto temp=q.top(); q.pop();
        auto temp1=q1.top(); q1.pop();
        ans[temp.second]=b[temp1.second];
    }
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    return 0;
}

真爱粉Tk(三)

image.png

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],s[N],cnt2[N],cnt5[N],n,k;
bool check(LL x)
{
    LL sum=0,cnt=1,p=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i]>x) return false;
        if(sum+s[i]+p*cnt5[i]>x)
        {
            cnt++;
            sum=s[i],p=cnt2[i];
        }else sum=sum+s[i]+p*cnt5[i],p+=cnt2[i];
    }
    return cnt<=k;
}
int main(void)
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        string ss; ss=to_string(a[i]);
        for(int j=0;j<ss.size();j++)
        {
            if(ss[j]=='2') cnt2[i]++;
            if(ss[j]=='5') cnt5[i]++,s[i]+=cnt2[i];
        }
    }
    LL l=0,r=1e18;
    while(l<r)
    {
        LL mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    cout<<l;
    return 0;
}

Tk的染色树

image.png 可以发现,答案和叶子有关,偶数的话,选所有叶子便可以。 奇数的话也是全选,那么此时我们是不是还得再选一个点才行,那么从所有中找到最小的数即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
LL w[N],d[N],sum,cnt,n;
int main(void)
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    for(int i=1;i<=n-1;i++)
    {
        int a,b; cin>>a>>b;
        d[a]++,d[b]++;
    }
    for(int i=1;i<=n;i++)
        if(d[i]<=1) cnt++,sum+=w[i];
    if(cnt&1)
    {
        LL temp=1e12;
        for(int i=1;i<=n;i++) temp=min(temp,w[i]);
        cout<<sum+temp;
    }else cout<<sum;
    return 0;
}

Tk的排列间异或

image.png 可以发现,只有一种解可以没有使得异或没有任何抵消。那么从大到小找,当前数为0的位置找到都为1的数,便可以没有任何的消耗。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
int a[N],n;
int main(void)
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    map<int,int>mp;
    for(int i=n;i>=1;i--)
    {
        if(mp[i]) continue;
        int temp=i,w=1,ans=0;
        while(temp)
        {
            if(temp%2==0) ans+=w;
            w=w*2,temp/=2;
        }
        mp[i]=ans,mp[ans]=i;
    }
    for(int i=1;i<=n;i++) cout<<mp[a[i]]<<" ";
    return 0;
}