2019年湘潭大学程序设计竞赛(重现赛)

题目链接:https://ac.nowcoder.com/acm/contest/893#rank

白天做题做的很自闭,晚上硬着头皮做了,还好都做出来了。

A:Who's better?

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int x1,x2,y1,y2,z1,z2;
    cin>>x1>>y1>>z1>>x2>>y2>>z2;
    if(x1>x2 || x1==x2&&y1<y2 || x1==x2&&y1==y2&&z1<z2) cout<<"1"<<endl;
    else if(x1==x2&&y1==y2&&z1==z2)cout<<"God\n";
    else cout<<"2"<<endl;
  return 0;
}

B:Number

小模拟,不够除,就直接加到整除

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        ll ans=0;
        cin>>n;
        int m;
        while(n>1)
        {
            if(n%10==0) n=n/10,ans++;
            else
            {
                m=n/10;
                ans+=(m+1)*10-n;
                n=(m+1)*10;
            }
        }
        cout<<ans<<endl;
     }
    return 0;
}

C:Math Problem

才192,直接从l和r向右,向左枚举找到第一个符合的,在等差求和即可,当时傻逼了,二分求的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int l,r;
        cin>>l>>r;
        ll al=-1,ar=-1;
        ll l_=0,r_=1e9;
        while(l_<=r_)
        {
            ll mid=(r_+l_)>>1;
            if(mid*192+1>=l)
            {
                al=mid*192+1;
                r_=mid-1;
            }
            else
            {
                l_=mid+1;
            }
        }
        l_=0,r_=1e9;
        while(l_<=r_)
        {
            ll mid=(r_+l_)>>1;
            if(mid*192+1<=r)
            {
                ar=mid*192+1;
                l_=mid+1;
            }
            else
            {
                r_=mid-1;
            }
        }
    //  cout<<al<<" "<<ar<<endl;
        if(al>ar) cout<<"0\n";
        else
        {
            cout<<(al+ar)*(ar-al+192)/192/2<<endl; 
        }
    }
    return 0;
}

D:Stone

思维,最大的去除,其他堆算一次即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        ll x,sum=0,maxx=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&x);
            sum+=x;
            maxx=max(x,maxx);
        }
        cout<<sum-maxx<<endl;
    }
    return 0;
}

E:Watermelon

我是先枚举lililalala前面的人吃掉了多少,剩下p,然后二分判断的,因为要满足p = k * lililalala的 + k * ([n-1, sum - lililalala]  ),看是否能找到符合条件的k

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m;
int a[N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        int id=1;
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);sum+=a[i];
            if(a[i]>a[id])
            {
                id=i;
            }
        }
        if(n==1)
        {
            printf("YES\n");
            continue;
        }
        sum-=a[id];
        int cnt=0;
        for(int i=1;i<id;i++)cnt+=a[i];
        int flag=0;
        if(cnt>=m && m>=id-1)
        {
            printf("YES\n");
            continue;
        }
        if(m<id-1)
        {
            printf("NO\n");
            continue;
        }
        double tmp,t;
         
        for(int i=id-1;i<=cnt;i++)
        {
            tmp=m-i;
            int l=1,r=tmp/a[id];
            while(l<=r)
            {
                int mid=(r+l)>>1;
                if(tmp/mid-a[id] < n-1)
                {
                    r=mid-1;
                }
                else if(tmp/mid-a[id]>sum)
                {
                    l=mid+1;
                }
                else
                {
                    flag=1;
                    break;
                }
            }
            if(flag) break;
        }
        printf(flag?"YES\n":"NO\n");
    }
    return 0;
}

F:Black & White

我是尺取做的,先把连续1和0的区间记录下来,然后用m取填补,最后有可能计算出来的超过了n,和n取个较小值即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{
    int l,r;
}a[N],b[N];
int n,m;
int len;
char s[100100];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        len=0;
        for(int i=1;i<=n;)
        {
            if(s[i]=='1')
            {
                len++;
                b[len].l=i;
                while(i<=n&&s[i]=='1') i++;
                b[len].r=i-1;
            }
            else i++;
        }
 
        b[len+1].l=2000000000+10;
        int ll=1,rr=2;
        int nn=len;
        int cnt=m;
        int ans=0;
        int maxx;
        while(rr<=nn+1)
        {
            while(rr<=nn+1 && cnt>=0)
            {
                ans=max(ans,b[rr - 1].r - b[ll].l + 1 + cnt);
                cnt-=b[rr].l-b[rr-1].r-1;
                rr++;
            }
            cnt += b[ll+1].l - b[ll].r - 1;
            ll++;
         
        }
        maxx=ans;
        ans=0;
        len=0;
        for(int i=1;i<=n;)
        {
            if(s[i]=='0')
            {
                len++;
                b[len].l=i;
                while(i<=n&&s[i]=='0') i++;
                b[len].r=i-1;
            }
            else i++;
        }
 
        b[len+1].l=2000000000+10;
        ll=1,rr=2;
        nn=len;
        cnt=m;
        while(rr<=nn+1)
        {
            while(rr<=nn+1 && cnt>=0)
            {
                ans=max(ans,b[rr - 1].r - b[ll].l + 1 + cnt);
                cnt-=b[rr].l-b[rr-1].r-1;
                rr++;
            }
            cnt += b[ll+1].l - b[ll].r - 1;
            ll++;
         
        }
        maxx=max(maxx,ans);
        maxx=min(maxx,n);
        printf("%d\n",maxx);
    }
    return 0;
}

G:Truthman or Fakeman

若A说B为诚实的,那么 要么A和B都是诚实的,要么都不诚实

若A说B不诚实的,那么A和B,其中一个诚实,一个不诚实

所以A和B建边,每个独立集,有一个确定下来其他的就都确定了,枚举每个独立集中的一个,看他为诚实和不诚实的,取个该独立集得到诚实的人数较多的情况即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{
    int to,nex;
    bool p;
}e[N*2];
 
int n,m;
int vis[N];
int flag;
int head[N],len;
void add(int x,int y,bool z)
{
    e[len].to=y;
    e[len].p=z;
    e[len].nex=head[x];
    head[x]=len++;
}
int s1,s2;
void dfs(int u,int f)
{
    for(int i=head[u];i!=-1;i=e[i].nex)
    {
        if(e[i].to==f) continue;
        if(vis[e[i].to]!=-1)
        {
            if(e[i].p==1 && vis[u] != vis[e[i].to] ) flag=0;
            if(e[i].p==0 && vis[u] == vis[e[i].to] ) flag=0;
            continue;
        }
        if(e[i].p==1) vis[e[i].to]=vis[u];
        else vis[e[i].to]=!vis[u];
        if(vis[e[i].to]==1)s1++;else s2++;
        dfs(e[i].to,u);
        if(!flag)
        {
            vis[e[i].to]=-1;
            return;
        }
    }
}
void dfs1(int u,int f)
{
    vis[u]=-1;
    for(int i=head[u];i!=-1;i=e[i].nex)
    {
        if(e[i].to==f) continue;
        if(vis[e[i].to]==-1) continue;
        dfs1(e[i].to,u);
    }
}
int main()
{
    int T;
    int x,y;
    int z;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            head[i]=-1;
            vis[i]=-1;
        }
        len=0;
         
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        flag=1;
         
        for(int i=1;i<=n;i++)
        {
            flag=1;
            if(vis[i]!=-1) continue;
            vis[i]=1;
            s1=0,s2=0;
            s1++;
            dfs(i,0);
            if(!flag)
            {
                flag=1;
                vis[i]=0;
                dfs(i,0);
                if(!flag) break;
            }
            else
            {
                int maxx=s1-s2;
                s1=0,s2=0;
                dfs1(i,0);
                flag=1;
                vis[i]=0;
                s2++;
                dfs(i,0);
            //  cout<<maxx<<" "<<s1<<" "<<s2<<endl;
                if(flag)
                {
                    if(s1-s2<maxx)
                    {
                        dfs1(i,0);
                        vis[i]=1;
                        dfs(i,0);
                    }
                }
            }
        }
        if(flag==0) printf("-1\n");
        else
        {
            for(int i=1;i<=n;i++)
            {
                printf("%d",vis[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

H:Chat

预处理+分组背包

我是先把m为0时的情况算出来,就是每天最右1-最左1的和,然后把每天让女生生气k次,减少的时间最多的情况算出来,因为每天选的区间只有一个,所以让女生生气也只是左连续和右连续,最后求个让女生生气k次,得到最大的时间,因为每一天只能确定一个,所以是个分组背包

#include<bits/stdc++.h>
using namespace std;
char s[210];
int dp[210][210];
struct node{
    int w,v;
}a[210][210];
int len[210];
int n,m,k;
int l[210],r[210];
int cmp(const node &xx,const node &yy)
{
    return xx.w<yy.w;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int sum=0;
        int ll,rr;
        int flag,cnt;
         
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            len[i]=0;
            ll=m+1,rr=0;
            flag=0;
            cnt=0;
            for(int j=1;j<=m;j++)
            {
                if(s[j]=='1')
                {
                    if(flag)
                    {
                        l[flag]=cnt;
                //      cout<<flag<<" "<<cnt<<endl;
                    }
                    ll=min(ll,j),rr=max(rr,j),flag++;
                     
                }
                if(flag) cnt++;
                 
            }
            if(flag) l[flag]=rr-ll+1,sum+=rr-ll+1;
            else continue;
            flag=0;
            cnt=0;
            for(int j=m;j>=1;j--)
            {
                if(s[j]=='1')
                {
                    if(flag)
                    {
                        r[flag]=cnt;
        //              cout<<flag<<" "<<cnt<<endl;
                    }
                    flag++;
                }
                if(flag) cnt++;
            }
            r[flag]=rr-ll+1;
            if(flag)
            {
                for(int j=1;j<flag;j++)
                {
                    cnt=0;
                    for(int k=0;k<=j;k++)
                    {
                //      cout<<k<<" "<<l[k]<<" * "<<r[j-k]<<endl;
                        cnt=max(cnt,l[k]+r[j-k]);
                    }
                //  cout<<j<<" "<<cnt<<endl;
                    a[i][++len[i]].w=j;
                    a[i][len[i]].v=cnt;
                }
                a[i][++len[i]].w=flag;
                a[i][len[i]].v=rr-ll+1;
            }
            sort(a[i]+1,a[i]+1+len[i],cmp);
             
        }
        memset(dp,0,sizeof(dp));
    //  sort(a+1,a+1+len,cmp);
        for(int i=1;i<=n;i++)
        {
            for(int kk=k;kk>=0;kk--)
            {
                dp[i][kk]=dp[i-1][kk];
                for(int j=1;j<=len[i];j++)
                {
                    if(a[i][j].w>kk) break;
                    dp[i][kk]=max(dp[i][kk],dp[i-1][kk-a[i][j].w]+a[i][j].v);
                }
            }
                 
        }
    //  cout<<sum<<" "<<dp[n][k]<<endl;
        printf("%d\n",sum-dp[n][k]);
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值