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

84 阅读3分钟
题目难度知识点
A 小苯跑外卖签到
B 小苯的区间删除签到
C 小苯的数字消除思维
D 小苯的数字集合★★思维
E 小苯的Polygon★★思维 DP
F 小苯的线性dp★★思维/前后缀

image.png

D题写了个爆搜,理论上发现不会搜几步但是T了红温了就打游戏去了。

小苯跑外卖

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    int x,y; cin>>x>>y;
    cout<<(y+x-1)/x;
    return 0;
}

小苯的区间删除

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL a[N],t,n,k;
int main(void)
{
    scanf("%lldd",&t);
    while(t--)
    {
        LL ans=0;
        scanf("%lld%lld",&n,&k);
        for(int i=0;i<n;i++) scanf("%lld",&a[i]),ans+=max(0ll,a[i]);
        printf("%lld\n",ans);
    }
    return 0;
}

小苯的数字消除

不能消除的最后一定是 010101010类似于这种

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    int t; cin>>t;
    while(t--)
    {
        int n;
        string s; cin>>n>>s;
        stack<char>st;
        for(int i=0;i<n;i++)
        {
            if(st.size()&&st.top()==s[i]) st.pop();
            else st.push(s[i]);
        }
        cout<<st.size()/2<<'\n';
    }
    return 0;
}

小苯的数字集合

image.png 结论最大为3,因为 x&y,x&y, (x&y)^(x&y) 最多三步。特判就行。

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
void solve()
{
    int x,y; cin>>x>>y;
    if( (x&y)==0 || (x^y)==0 )
    {
        cout<<1<<'\n';
    }else
    {
        int flag=0;
        int temp1=x&y,temp2=x^y,temp3=gcd(x,y);
        if((temp1&x)==0 || (temp1&y)==0 || (temp1^x)==0 || (temp1^y)==0 ) flag=1;
        if((temp2&x)==0 || (temp2&y)==0 || (temp2^x)==0 || (temp2^y)==0 ) flag=1;
        if((temp3&x)==0 || (temp3&y)==0 || (temp3^x)==0 || (temp3^y)==0 ) flag=1;
        if(flag) cout<<2<<'\n';
        else cout<<3<<'\n';
    }
}
int main(void)
{
    int t; cin>>t;
    while(t--) solve();
    return 0;
}

小苯的Polygon

image.png 三角形满足的条件也适用于多边形,先排序然后再从小到大排序,枚举a[i]表示当前多边形的最长边,那么意味着需要从前边集合中抽出一个子集满足大于a[i]故可以用dp[j]表示第j个数值能不能用前i-1个数可以凑出来且大于a[i],只要满足break,便找到了以当前边作为最长边用前面的数可以构成满足条件的最小多边形。

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int dp[N],a[N],n,t;
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    memset(dp,0,sizeof dp);
    dp[0]=1;
    int ans=1e9;
    for(int i=1;i<=n;i++)
    {
        for(int j=a[i]+1;j<=100*n;j++)
        {
            if(dp[j])
            {
                ans=min(ans,j+a[i]);
                break;
            }
        }
        for(int j=n*100;j>=a[i];j--)
            if(dp[j-a[i]]) dp[j]=1;
    }
    if(ans==1e9) puts("-1");
    else cout<<ans<<'\n';
}
int main(void)
{
    cin>>t;
    while(t--) solve();
}

小苯的线性dp

image.png 最终一定是一个大数减一个小数,且小数一定是一个不可能是合并后的数。 那么一般情况是 前边合并 最小数 后边合并 。max(前边合并长度不超过和并次数+1的最大前缀-后边合并长度不超过和并次数+1的最大后缀)-a[i]。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3*3+10;
typedef long long int LL;
LL a[N],l[N],r[N],s[N];
int n;
void solve()
{
    cin>>n;
    for(int i=0;i<=n+1;i++) l[i]=0,r[i]=0,s[i]=0;
    for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
    for(int k=1;k<=n-2;k++)//合并后的区间最大长度为k
    {
        for(int i=1;i<=n;i++) l[i]=max(l[i-1],s[i]-s[max(0,i-k)]);
        for(int i=n;i>=1;i--) r[i]=max(r[i+1],s[min(n,i+k-1)]-s[i-1]);
        LL ans=0;
        for(int i=1;i<=n;i++)
        {
            ans=max(ans,max(l[i-1],r[i+1])-a[i]);
        }
        cout<<ans<<" ";
    }
    cout<<max({s[n]-a[1]-a[1],s[n-1]-a[n]})<<" 0"<<'\n';
}
int main(void)
{
    int t; cin>>t;
    while(t--) solve();
    return 0;
}