Codeforces Round #640 (Div. 4) 题解

博客主要解析了Codeforces Div. 4比赛中的7道题目,包括题意概述、数据范围、题解和代码实现。涉及的题目类型包括数论、组合优化、模拟等,适合初学者练习。
摘要由CSDN通过智能技术生成

CF出div4了,我的青春结束了

第一场div4的话就我的体验来说前面几道比较偏模拟,后面几道比较偏构造思维,个人体验还行

(注意:由于还未终测所以代码不保证正确性,AB以外的题没写题意简述)

本文同步发布于个人博客

A. Sum of Round Numbers

题意简述

T T T组数据,给你一个数字 n n n,要你用最少的round number表示出 n n n,round number意思是最左边不为 0 0 0,其他都为 0 0 0的数字,其实就是 k ⋅ 1 0 x k\cdot 10^x k10x这样

数据范围

1 ≤ t ≤ 1 0 4 , 1 ≤ n ≤ 1 0 4 1\leq t\leq 10^4,1\leq n\leq 10^4 1t104,1n104


题解

很显然,直接把每位拆开来就行,我的写法是在计算第 k k k位数是几的同时维护一下base,意思是现在的数需要乘base


代码
int T,n;
vector<int> a;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n;
        int ans=0;a.clear();
        int base=1;
        while(n)
        {
            if(n%10!=0) 
            {
                a.push_back((n%10)*base);
                ans++;
            }
            n/=10;
            base*=10;
        }
        cout<<ans<<endl;
        for(int i=0;i<a.size();i++) cout<<a[i]<<" ";
        cout<<endl;
    }
    return 0;
}

B. Same Parity Summands

题意简述

T T T组数据,给定 n n n k k k,求 n n n可不可以被 k k k个奇数或者 k k k个偶数表示,可以输出YES,否则输出NO

数据范围

1 ≤ t ≤ 1000 , 1 ≤ n ≤ 1 0 9 , 1 ≤ k ≤ 100 1\leq t\leq 1000,1\leq n\leq 10^9,1\leq k\leq 100 1t1000,1n109,1k100


题解

首先 k k k个同奇偶性的数其实取多大都不会影响性质,我取了 k − 1 k-1 k1个偶数,最后是偶数那就成立,奇数也一样, k − 1 k-1 k1个偶数取多少其实造不成影响,那么我们就尽量往小去取,取 k − 1 k-1 k1 1 1 1或者 k − 1 k-1 k1 2 2 2,再看剩下的数是否满足即可(假如取最小都已经大于 n n n则输出NO即可)


代码
int T;
int n,k;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n>>k;
        int temp=k-1;
        if(n-temp<=0) {puts("NO"); continue;}
        if((n-temp)%2==1)
        {
            puts("YES"); 
            for(int i=1;i<k;i++) cout<<1<<" ";
            cout<<n-temp<<endl;
            continue;
        }
        temp=(k-1)*2;
        if(n-temp<=0) {puts("NO"); continue;}
        if((n-temp)%2==0)
        {
            puts("YES"); 
            for(int i=1;i<k;i++) cout<<2<<" ";
            cout<<n-temp<<endl;
            continue;
        }
        puts("NO");
        continue;
    }
    return 0;
}

C. K-th Not Divisible by n

题解

n n n个数会对答案产生 n − 1 n-1 n1的贡献,我们先算出大致的区间,即 k k k最后落在的区间,前面的每一整段都会多加1,最后加上剩余的即可

我们首先算比 k k k大需要多少区间,直接 ⌈ k n − 1 ⌉ \lceil \frac{k}{n-1}\rceil n1k之后减一就是小于等于 k k k的最大的区间数量,这每一个区间都会比原来多产生1的贡献,即这一段会变成 ( ⌈ k n − 1 ⌉ − 1 ) ⋅ n (\lceil \frac{k}{n-1}\rceil -1)\cdot n (n1k1)n之后再用 k − ⌈ k n − 1 ⌉ k-\lceil \frac{k}{n-1}\rceil kn1k即剩下来的,这一部分不会多,和原来一样,直接加上即可

另外代码里有一个细节, ⌈ a b ⌉ = ⌊ a + b − 1 b ⌋ \lceil \frac{a}{b}\rceil = \lfloor \frac{a+b-1}{b}\rfloor ba=ba+b1这样直接用默认的向下取整就好了


代码
ll T,n,k;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n>>k;
        if(k<=n-1) cout<<k<<endl;
        else
        {
            ll t=1;
            t=(k+n-2)/(n-1);
            t--;
            ll temp=t*n-t;
            ll rest=k-temp;
            cout<<t*n+rest<<endl;
        }
    }
    return 0;
}

D. Alice, Bob and Candies

题解

这题就是一个模拟题,按照题意去写就好,我这里是用了类似双指针的方法,维护 l l l r r r分别往左右移,不断while即可,这个模拟题注意细节即可,直接贴一下代码


代码
const int maxn=1050;
int T,n;
int a[maxn];
int main()
{
    cin>>T;
    while(T--)
    {
        rd(n);
        rep(i,1,n) rd(a[i]);
        int ans=0;
        int l=0,r=n+1;
        int pre=0;
        int sum1,sum2;sum1=sum2=0;
        if(n==1) 
        {
            cout<<1<<" "<<a[1]<<" "<<0<<endl;
            continue;
        }
        if(n==2)
        {
            cout<<2<<" "<<a[1]<<" "<<a[2]<<endl;
            continue;
        }
        while(l<r)
        {
            l++;
            int t1=a[l];
            while(l+1<r&&t1<=pre) l++,t1+=a[l];
            if(t1<=pre||l+1==r)
            {
                ans++;
                sum1+=t1;
                break;
            }
            else sum1+=t1,ans++;
            pre=t1;
            r--;
            int t2=a[r];
            while(r-1>l&&t2<=pre) r--,t2+=a[r];
            if(t2<=pre||r-1==l)
            {
                ans++;
                sum2+=t2;
                break;
            }
            else sum2+=t2,ans++;
            pre=t2;
        }
        cout<<ans<<" "<<sum1<<" "<<sum2<<endl;
    }
    return 0;
}

E. Special Elements

题解

这道题我们观察到 n ≤ 8000 n\leq 8000 n8000,好像可以 O ( n 2 ) O(n^2) O(n2)但又感觉有点吃紧,但是题面一开始特意强调了一堆卡时间和空间,那感觉就应该是 n 2 n^2 n2了,加点优化应该就行

这题的重点是 1 ≤ a i ≤ n 1\leq a_i\leq n 1ain,这就意味着一段区间和大于 n n n就肯定不会对答案产生贡献,所以我们可以直接用一个数组去当作map(注意这题你用map之类的数据结构会被卡),先统计前缀和,然后 n 2 n^2 n2枚举区间的时候如果 s j − s i ≤ n s_j-s_i\leq n sjsin就记录进map否则不管,最后统计答案即可


代码
const int maxn=10005;
int T;
int n,a[maxn],s[maxn];
int mp[maxn];
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=0;i<=n;i++) mp[i]=0;
        s[0]=0;
        rep(i,1,n) 
        {
            rd(a[i]);
            s[i]=s[i-1]+a[i];
            if(i>1&&s[i]<=n) mp[s[i]]=1;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i+2;j<=n;j++)
                if(s[j]-s[i]<=n) mp[s[j]-s[i]]=1;
        }
        int ans=0;
        rep(i,1,n) if(mp[a[i]]) ans++;
        printf("%d\n",ans);
    }
    return 0;
}

F. Binary String Reconstruction

题解

这题比较简单的构造方法应该是,首先 n 2 + 1 n_2+1 n2+1 1 1 1,之后 n 0 + 1 n_0+1 n0+1 1 1 1,注意这时候已经产生了一个 n 1 n_1 n1,最后看看 n 1 n_1 n1还差几个交错输出 10 10 10即可

当然因为一开始已经产生了一个 n 1 n_1 n1所以 n 1 n_1 n1 0 0 0时候要特判一下,因为 n 1 n_1 n1 0 0 0所以 n 0 n_0 n0 n 2 n_2 n2不可能同时出现


代码
const int maxn=505;
int T,a,b,c;
int t[maxn];
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>a>>b>>c;
        if(b==0)
        {
            if(c>0) for(int i=1;i<=c+1;i++) printf("1");
            if(a>0) for(int i=1;i<=a+1;i++) printf("0");
            cout<<endl;
            continue;
        } 
        for(int i=1;i<=c+1;i++) printf("1");
        for(int i=1;i<=a+1;i++) printf("0");
        for(int i=1;i<=b-1;i++) 
        {
            if(i&1) printf("1");
            else printf("0");
        }
        cout<<endl; 
    }
    return 0;
}

G. Special Permutation

题解

这道题想到分成奇数偶数然后手玩推一推应该就出来了,我的构造方案是从最大的一个奇数开始往前推一直到1,然后跳到4,然后跳到2,这样后面就可以6,8然后一直到最后,小的数注意特判一下即可


代码
int T,n;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n;
        if(n==2||n==3) puts("-1");
        else if(n==4) puts("3 1 4 2");
        else if(n==5) puts("5 3 1 4 2");
        else
        {
            int t=n;
            if(t%2==0) t--;
            for(int i=t;i>=1;i-=2) cout<<i<<" ";
            cout<<4<<" "<<2<<" "<<6<<" ";
            for(int i=8;i<=n;i+=2) cout<<i<<" ";
            cout<<endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值