牛客小白月賽27部分題解

清風紫雪發表於2020-08-23

B樂團派對

題目:https://ac.nowcoder.com/acm/contest/6874/B

題解:貪心的思路,將能力值從小到大排序,先判斷能否組成一個樂隊,從後開始遍歷往前,如果可以得到一個樂隊,那麼標記此時的位置。否則,輸出-1

標記位置後,開始從頭遍歷到標記的位置,看最多能組成多少隊,在標記位置之前的如果組不成一個就融入到最後那個樂隊。

程式碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
ll n,a[N],i,j;
ll maxn=0;
ll ans=0;
int main()
{
    cin>>n;
    for(i=0;i<n;i++)
        cin>>a[i];
    sort(a,a+n);
    ll cnt=0;
    ll end;
    for(i=n-1;i>=0;i--)
    {
        maxn=max(maxn,a[i]);
        cnt++;
        if(cnt==maxn)
        {
            ans++;
            end=i;
            break;
        }
    }
    if(ans==0)
        cout<<"-1"<<endl;
    else
    {
        maxn=0;
        cnt=0;
        for(i=0;i<end;i++)
        {
            maxn=max(maxn,a[i]);
            cnt++;
            if(cnt==maxn)
            {
                cnt=0;
                maxn=0;
                ans++;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

D巔峰對決

題目:https://ac.nowcoder.com/acm/contest/6874/D

題解:一道求最值線段樹的問題

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
typedef long long ll;
ll tree[MAXN*4];
ll ans[MAXN*4];
ll n,q;
void pushUp(ll p)
{
    tree[p]=tree[p<<1]+tree[p<<1|1];
}
void build(ll l,ll r,ll p)
{
    if(l==r)
    {
        cin>>tree[p];
        ans[p]=tree[p];
        return ;
    }
    ll mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
    pushUp(p);
    ans[p]=min(ans[p<<1],ans[p<<1|1]);
}

//區間求和
ll query(ll l,ll r,ll p,ll i,ll j)
{
    if(j<l||i>r)
        return 0;
    if(l>=i&&j>=r)
        return tree[p];
    ll ans=0;
    ll mid=(l+r)>>1;
    if(mid>=i)
        ans+=query(l,mid,p<<1,i,j);
    if(mid<j)
        ans+=query(mid+1,r,p<<1|1,i,j);
    return ans;
}
//單點更新
void update(ll l,ll r,ll p,ll i,ll j)
{
    if(l==r)
    {
        tree[p]=j;
        ans[p]=j;
        return;
    }
    ll mid=(l+r)>>1;
    if(mid>=i)
        update(l,mid,p<<1,i,j);
    else
        update(mid+1,r,p<<1|1,i,j);
    pushUp(p);
    ans[p]=min(ans[p<<1],ans[p<<1|1]);
}
//詢問區間最值
ll ask(ll l,ll r,ll p,ll a,ll b)
{
    if(b<l||a>r) return 1e18;
    if(l>=a&&b>=r)
        return ans[p];
    ll v1=0,v2=0;
    ll mid=(l+r)>>1;
    v1=ask(l,mid,p<<1,a,b);
    v2=ask(mid+1,r,p<<1|1,a,b);
    return min(v1,v2);
}
int main()
{
    ll op,x,y;
    cin>>n>>q;
    build(1,n,1);
    while(q--)
    {
        cin>>op>>x>>y;
        if(op==1)
            update(1,n,1,x,y);
        else
        {
            ll minx=ask(1,n,1,x,y);
            ll sum=query(1,n,1,x,y);
            ll len=y-x+1;
            len=len*(minx*2+len-1)/2;
            if(len==sum)
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
    }
    return 0;
}

E使徒來襲

題目:https://ac.nowcoder.com/acm/contest/6874/E

題解:只要求出戰鬥力之積的開三次方根的3倍即可

程式碼:

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n;
    scanf("%d",&n);
    printf("%.3lf\n",3*pow(n,1.0/3));
    return 0;
}

F核彈劍仙

題目:https://ac.nowcoder.com/acm/contest/6874/F

題解:dfs問題+vector陣列解決,先儲存每一位比自己武器強的武器編號。

然後從第一個往後逐個深搜,遞迴搜尋每一個比他強的武器編號,並且要標記每一個比他強的武器編號,否則會有重複計算,而且不能使用記憶化陣列,會導致重複計算而且標記不全。

程式碼:

#include<bits/stdc++.h>
using namespace std;
int n,m,a,b;
int v[1010];
vector<int> g[1010];
int dfs(int x)
{
    v[x]=1;
    int ans=0;
    for(int i=0;i<g[x].size();i++)
    {
        int tmp=g[x][i];
        if(!v[tmp])
        {
            ans+=dfs(tmp);
            v[tmp]=1;
            ans++;
        }
    }
    return ans;
}

int main()
{
    int i,j;
    cin>>n>>m;
    for(i=0;i<m;i++)
    {
        cin>>a>>b;
        g[b].push_back(a);
    }
    for(i=1;i<=n;i++)
    {
        memset(v,0,sizeof(v));
        cout<<dfs(i)<<endl;
    }
    return 0;
}

G虛空之力

題目:https://ac.nowcoder.com/acm/contest/6874/G

題解:輸入時統計每個字母的個數,優先選擇k+2*ing的數字,找出i,n,g三者最小的除以2,再將此數與k比較,如果此數大於k的個數,表示最多有2*k個,否則在判斷剩餘的k的個數,與剩餘的i,n,g三者中較小的個數,再加上這個就為最終的答案。

程式碼:

#include<bits/stdc++.h>
using namespace std;
string s;
int k,i,n,g,m;
int main()
{
    cin>>m;
    cin>>s;
    int j=0;
    for(j=0;j<m;j++)
    {
        if(s[j]=='k')
            k++;
        else if(s[j]=='i')
            i++;
        else if(s[j]=='n')
            n++;
        else if(s[j]=='g')
            g++;
    }
    int ans=0;
    int minx=min(i,min(n,g));
    minx=minx/2;
    if(k>=minx)
    {
        ans+=minx*2;
        i-=minx*2;
        n-=minx*2;
        g-=minx*2;
        k-=minx;
        int f=min(k,min(i,min(n,g)));
        ans+=f;
    }
    else
    {
        ans+=k*2;
    }
    cout<<ans;
    return 0;
}

H社團遊戲

題目:https://ac.nowcoder.com/acm/contest/6874/H

題解:二維字首和+二分
首先我們得知道,對於任意一個小寫字母,其正方形邊長越長,那麼在這個矩陣中找到該字母個數和超過k的正方形的可能性也就越大,因此這個邊長具有單調性可以二分。
所以我們對每個小寫字母預處理一個二維字首和,然後列舉左上角,之後二分邊長。對於每次二分的邊長,我們判斷其形成的正方形是否符合任意一類小寫字母個數之和不超過k就行了。

程式碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,k;
char s[510][510];
ll a[26][510][510];

bool check(ll x1,ll y1,ll x2,ll y2)
{
    for(int i=0;i<26;i++)
    {
        if(a[i][x2][y2]-a[i][x1-1][y2]-a[i][x2][y1-1]+a[i][x1-1][y1-1]>k)
            return false;
    }
    return true;
}


int main()
{
    ll i,j,f,l,r,mid;
    cin>>n>>m>>k;
    for(i=1;i<=n;i++)
    {
        scanf("%s",s[i]+1);
    }
    for(f=0;f<26;f++)
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
                a[f][i][j]=a[f][i-1][j]+a[f][i][j-1]-a[f][i-1][j-1]+(s[i][j]==f+'a');
        }
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            l=1;r=min(n-i+1,m-j+1);
            while(l<r)
            {
                mid=(l+r)>>1;
                if(check(i,j,i+mid,j+mid))
                    l=mid+1;
                else
                    r=mid;
            }
            cout<<l;
            if(j!=m)
                cout<<" ";
        }
        cout<<endl;
    }
    return 0;
}

J逃跑路線

題目:https://ac.nowcoder.com/acm/contest/6874/J

題解:首先分析最後橫座標要&上的那堆數,不妨先計算那堆數相&的結果,會發現為1,燃火再看每個a[i]的資料範圍,1010000次方,絕對會爆0,因此不能用long long得用striing字串來儲存,由於最後我們需要與1&,我們只需要知道最後一位的相加和即可。

程式碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans,x;
ll n;
string s;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>s;
        int t=s.length();
        ans=ans%10+(s[t-1]-'0')%10;
    }
    ans=ans&1;
    cout<<ans;
    return 0;
}

 

相關文章