2024牛客寒假算法基础集训营4个人补题题解(B、E)

B、左右互博

不能操作的情况有且仅有所有石子堆的石子个数只有1的时候,因此不管途中怎么操作,让所有石子堆都变成1的总操作次数是确定的。
即假设一共有\(n\)堆石子,石子总数为\(sum\),总操作次数为\((sum-n)\)次。
因此当\((sum-n)\)%\(2=0\)时一定在sweet操作完(或没有操作)后gui无法操作,sweet胜利;反之gui胜利。
时间复杂度:\(O(n)\)

c++ ac代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
const int inf=1e18;
const int M=1e9+7;
int a[N];
signed main() {
    int n;
    int cnt=0;
    cin >>n;
    for(int i=1;i<=n;i++)
    {
        cin >>a[i];
        cnt+=a[i];
    }
    if((cnt-n)%2==0)
        cout<<"sweet"<<'\n';
    else cout<<"gui"<<'\n';
    return 0;
}

E、漂亮数组

只要一段内出现过相加为\(k\)的倍数连续段,就直接在那段后面分割即可保持数量最大,那现在的问题就是如何去判断某段内有没有出现过相加和为\(k\)的倍数的连续段。
\(sum\)数组记录数组前缀和,变量\(now\)记录当前隔板(即上一次分割的位置),如果在当前段中出现了模\(k\)的相同值或者本身这一段的和就是\(k\)的倍数,就说明出现了相加为\(k\)的倍数的连续段,一段内的模\(k\)值可用\(map\)记录。分割完更新隔板位置,继续往后判断即可。
因为题意问的是分割后的漂亮数组数量,那就不用管其他多余段的情况,因为分割了多少刀本质上就是分出了多少个漂亮数组。
时间复杂度:\(O(nlogn)\)

c++ ac代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
const int inf=1e18;
const int M=1e9+7;
map<int,int> mp;
int a[N];
int sum[N];
signed main() {
    int n,k;
    cin >>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin >>a[i];
        sum[i]=sum[i-1]+a[i];
    }
    int now=0;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(mp[(sum[i]-sum[now])%k]!=0||(sum[i]-sum[now])%k==0)
        {
            ans++;
            mp.clear();
            now=i;
        }
        else
            mp[(sum[i]-sum[now])%k]++;
    }
    cout<<ans<<'\n';
    return 0;
}

posted @ 2024-02-24 21:18  Ritsuki  阅读(66)  评论(0)    收藏  举报