【Codeforces】#Round494 Div3

传送门:CodeforcesRound494Div3
做都做了,还是发一下题解吧。


A. Polycarp’s Pockets

数值相同的数的个数的最大值

#include<bits/stdc++.h>
using namespace std;
int n,a[102],ans,res;

int main(){
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;++i) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(i=1;i<=n;i=j+1){
        for(j=i;a[j+1]==a[i] && (j<n);++j);
        ans=max(ans,j-i+1);
    }
    printf("%d",ans);
}

B. Binary String Constructing

随便构造一下,多的放两边。
代码无脑巨丑,不宜观看

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

int a,b,x,n,ans[102];

int main(){
    int i,j;
    scanf("%d%d%d",&a,&b,&x);
    n=a+b;
    if(x%2==0){
       if(a==x/2){
         for(i=1;i<=x/2;++i) printf("10");
         b-=x/2;
         for(i=1;i<=b;++i) printf("1");
       }else if(b==x/2){
         for(i=1;i<=x/2;++i) printf("01");
         a-=x/2;
         for(i=1;i<=a;++i) printf("0");
       }else{
         for(i=1;i<=x/2;++i) printf("10");
         a-=x/2;b-=x/2;
         for(i=1;i<=a;++i) printf("0");
         for(i=1;i<=b;++i) printf("1");
       }
    }else{
       if(a==(x+1)/2){
         for(i=1;i<=(x+1)/2;++i) printf("01");
         b-=(x+1)/2;
         for(i=1;i<=b;++i) printf("1");
       }else if(b==(x+1)/2){
         for(i=1;i<=(x+1)/2;++i) printf("10");
         a-=(x+1)/2;
         for(i=1;i<=a;++i) printf("0");
       }else{
         for(i=1;i<=(b-(x+1)/2);++i) printf("1");
         for(i=1;i<=(x+1)/2;++i) printf("10");
         for(i=1;i<=(a-(x+1)/2);++i) printf("0");
       }
    }
}

C. Intense Heat

此题暴力可过。
非要作死写二分,细节没处理对还WA…

#include<bits/stdc++.h>
using namespace std;
#define db double
const int N=5050;
const db eps=1e-8;
int n,k;
db a[N],l,r,mid,ans,b[N],c[N],mx=-1.0,mn=5000.0;

inline bool check(db res)
{
    int i,j;
    b[1]=a[1]-res;c[1]=min(b[1],0.0);
    for(i=2;i<=n;++i){b[i]=a[i]-res*i;c[i]=min(c[i-1],min(b[i],0.0));}
    for(i=k;i<=n;++i) if(b[i]>=eps+c[i-k]) return true;
    return false;
}

int main(){
    int i,j;
    b[0]=0;a[0]=0.0;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;++i){
        scanf("%lf",&a[i]);
        mn=min(mn,a[i]);
        mx=max(mx,a[i]);
        a[i]=a[i-1]+a[i];
    }
    l=mn;r=mx;
    if(mn==mx){
        printf("%.7lf\n",mn);
        return 0;
    }
    while(r-l>=eps){
        mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%.7lf\n",l);
}

D. Coins and Queries

对于每个二进制位数上不为0的位 i i ,贪心用值小于等于1<<i的来替代,没有了就输出-1。
从大到小遍历保证最优。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,q,bin[33],v[33],tag[33];
int ans,res;

int main(){
    int i,j,ix,iy;
    bin[0]=1;for(i=1;i<=29;++i) bin[i]=bin[i-1]<<1;
    scanf("%d%d",&n,&q);
    for(i=1;i<=n;++i){
        scanf("%d",&ix);
        for(j=0;j<=29;++j){
            if(bin[j]==ix) break;
        }v[j]++;
    }
    while(q--){
        ans=0;
        for(i=0;i<=29;++i) tag[i]=v[i];
        scanf("%d",&ix);
        for(i=29;i>=0;--i)
            if((ix&bin[i]) && tag[i]>0){ix-=bin[i];tag[i]--;ans++;}
        for(i=29;i>=0;--i) if(ix&bin[i]){
            res=bin[i];
            for(j=i-1;j>=0;--j) if(tag[j]>0){
                if(res/bin[j]<=tag[j]){
                    tag[j]-=res/bin[j];
                    ans+=res/bin[j];
                    res=0;break;
                }else{
                    ans+=tag[j];
                    res-=tag[j]*bin[j];
                    tag[j]=0;
                }
            }
            if(res>0) break;
            else ix-=bin[i];
        }
        if(ix>0) printf("-1\n");
        else printf("%d\n",ans);
    }
}

E. Tree Constructing

数烷烃是真的有趣。
一开始想直接用等比数列判存在性,结果爆long long不说还WA…
所以当 nd n ≤ d 时,直接输出-1
我们先直接把直径建出来,然后在每个链上的点上长叶子点和链上最远点距离不超过直径的子树,限制一下k就好了。如果所有点都填满了还没凑到n,不就不存在了吗,
ps:好多特判啊

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,d,k,pos,lim;
int u[N],v[N],l;

inline void bb(){
    printf("NO\n");
    exit(0);
}

inline void dfs(int x,int fa,int dep)
{
    if(pos>n) return;
    u[++l]=x;v[l]=fa;
    if(pos==n || dep==lim) return;
    for(int i=1;i<k && pos<n;++i){pos++;dfs(pos,x,dep+1);}
}

int main(){
    int i,j;
    scanf("%d%d%d",&n,&d,&k);
    if(k==1){
        if(n>2 || d>1) bb();
        if(n==2 && d!=1) bb();
        if(n==1 && d>0) bb();
        printf("YES\n");
        if(n==2) printf("1 2");
        return 0;
    }
    if(n<=d) bb();pos=d+1;
    for(i=1;i<=d;++i) u[++l]=i,v[l]=i+1;
    for(i=2;i<=d && pos<n;++i){
        j=max(i-1,d+1-i);
        lim=d-j;
        for(j=1;j<k-1 && pos<n;++j){pos++;dfs(pos,i,1);} 
    }
    if(pos<n) bb();
    printf("YES\n");
    for(i=1;i<=l;++i) printf("%d %d\n",u[i],v[i]);
} 

F. Abbreviation

又看错题+理解错题意了!!

An abbreviation is a replacement of some segments of words with their first uppercase letters. In order to perform an abbreviation, you have to choose at least two non-intersecting equal segments of words, and replace each chosen segment with the string consisting of first letters of the words in the segment (written in uppercase).

注意at least two和non-intersecting TAT
不然就会像我一样WA而不知所措。
直接dp就好了,这题不难(如果你一遍就看清楚了题的话)。
作死双哈希不解释。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=170437,hh=29;
const int mob=460931,tt=47;
int a[305],b[305];
int ans,sum,n,m,cnt,f[305][305],ss[305];
char s[100020];

int main(){
    int i,j,k,pos,res,re;ll rx,ry;
    scanf("%d",&n);
    for(i=1;i<=n;++i){
        scanf("%s",s);
        m=strlen(s);
        rx=0;ry=0;ss[i]=ss[i-1]+m+1;
        for(j=0;j<m;++j){
            rx=(rx*hh%mod+s[j]-'a'+1)%mod;
            ry=(ry*tt%mob+s[j]-'a'+1)%mob;
        }
        a[i]=rx;b[i]=ry;
    }
    for(i=1;i<n;++i)
     for(j=i+1;j<=n;++j)
      if(a[i]==a[j] && b[i]==b[j]){
        if(!f[i-1][j-1]) f[i][j]=1;
        else{
            int q=min(j-i-1,f[i-1][j-1]);
            f[i][j]=q+1;
        }
      }
    ans=ss[n]-1;sum=ss[n]-1;
    for(i=1;i<n;++i)
     for(j=1;i+j<=n && j<=i;++j){
        res=ss[i]-ss[i-j]-j-1;
        if(!res) continue;
        cnt=1;
        for(k=i+j;k<=n;){if(f[i][k]>=j){cnt++;k+=j;}else k++;}
        if(cnt>1){
            ans=min(ans,sum-res*cnt);
        }
     }

    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值