Codeforces 1352


1352 A - Sum of Round Numbers

Prob1


把输入的数每个非零位代表的值都输出即可

例如 12034 ,输出10000 2000 30 4


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

void solve()
{
    int n,nd,siz=0,d=1;
    scanf("%d",&n);
    nd=n;
    while(nd)
    {
        if(nd%10!=0)
            siz++;
        nd/=10;
    }
    printf("%d
",siz);
    while(n)
    {
        if(n%10!=0)
            printf("%d ",(n%10)*d);
        n/=10;
        d*=10;
    }
    printf("
");
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}



1352 B - Same Parity Summands

Prob2


将数字 n 分成 k 个正整数,要求每个正整数的奇偶性相同,如果没办法分,输出 -1


也就是输出 k 个数,要么全是奇数要么全是偶数,且他们的和为 n

首先考虑输出奇数,贪心可得,我们可以先输出 k-1 个 1,最后输出一个 n-(k-1)

  所以方案的可行性就在于 n-(k-1) 是不是也是奇数

  如果是奇数,就按照这个方案输出即可

然后考虑输出偶数,贪心可得,我们可以先输出 k-1 个 2,最后输出一个 n-(k-1)*2

  所以方案的可行性就在于 n-(k-1)*2 是不是也是偶数

  如果是偶数,就按照这个方案输出即可

如果以上两种贪心方案都不可行,输出 -1


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

void solve()
{
    int n,k;
    scanf("%d%d",&n,&k);
    if(n-k+1>0&&(n-k+1)%2==1)
    {
        puts("YES");
        for(int i=1;i<k;i++)
            printf("1 ");
        printf("%d
",n-k+1);
    }
    else if(n-2*k+2>0&&(n-2*k+2)%2==0)
    {
        puts("YES");
        for(int i=1;i<k;i++)
            printf("2 ");
        printf("%d
",n-2*k+2);
    }
    else
        puts("NO");
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}



1352 C - K-th Not Divisible by n

Prob3


给定 n 和 k,要求输出第 k 个不能把 n 整除的正整数


明显,把从 1 开始的正整数排列中挖掉 k 的倍数,得到的就是所求序列

所以可以把每 n 个数进行分组,每组有效的数字有 n-1 个

例如此时 n=5 k=6

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

在原数列中,1 2 3 4 5 分为一组,6 7 8 9 10 分为一组,...

因为每组 4 个有效数字,所以 k=6 代表第 2 组的第 2 个有效数字

假设我们知道答案是第 x 组的第 y 个数字

那么就可以通过 (x-1)*n+y 求得这个数字

(x-1)*n 表示第 x 组之前有多少数字(包括无效)

(x-1)*n+y 则是所求答案(0 <= y <= n-1)

※ n k 到 x-1 y 的转化关系如下

x-1 = (k-1)/(n-1)*n

y = (k-1)%(n-1)+1

(代几个例子就能出来)


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

void solve()
{
    int n,k,ans;
    scanf("%d%d",&n,&k);
    printf("%d
",(k-1)/(n-1)*n+(k-1)%(n-1)+1);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}



1352 D - Alice, Bob and Candies

Prob4A
Prob4B


Alice 和 Bob 吃糖,Alice从左到右,Bob从右到左

第一步,Alice吃最左边的一堆糖,然后开始轮流吃

之后的每一步,那个人吃的糖数量之和要严格大于前一步另外一个人吃的糖数量之和

一旦变成大于,就可以切换到另外一个人吃糖

如果最后一个人没法吃满,那就吃完剩余的所有糖,结束操作

最后输出进行的轮数、两个人分别吃了多少糖


模拟题,可以存在数组里使用双指针,通过指针是否重合来判断是否吃完

我用的是栈+队列来分别模拟从右到左和从左到右


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

void solve()
{
    int n,d,cnt=0,alice=0,bob=0,les,lasteat=0,eat=0,turn=0;
    queue<int> q;
    stack<int> s;
    
    scanf("%d",&n);
    les=n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&d);
        q.push(d);
        s.push(d);
    }
    
    while(les>0) //只要还有剩余,就继续下去
    {
        cnt++; //轮数+1
        eat=0;
        if(turn==0) //Alice吃
        {
            while(les>0&&eat<=lasteat) //只要还有剩余,且吃的数量小于等于上一轮吃的数量
            {
                eat+=q.front();
                q.pop();
                les--;
            }
            lasteat=eat; //更新上一轮吃的数量
            alice+=eat; //加在Alice吃的上面
        }
        else //Bob吃
        {
            while(les>0&&eat<=lasteat)
            {
                eat+=s.top();
                s.pop();
                les--;
            }
            lasteat=eat;
            bob+=eat;
        }
        turn=1-turn; //轮流切换
    }
    printf("%d %d %d
",cnt,alice,bob);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}



1352 E - Special Elements

Prob5


给定一个数组 a

如果数组中的某个数恰好等于某个长度大于等于2的连续子序列之和

那么就称这个数是Special的

问数组中有多少Special的数


考虑到 n<=8000 且 SUM(n)<=8000

O(n^2^) 的解法在最坏情况下(也就是1个样例,n=8000)也能保证不超过时间限制

所以直接暴力处理出每个长度大于等于2的连续子序列之和

加入 b 数组,b[i] 记录数字 i 在数组中出现多少次

加入 sum 数组,处理前缀和,便于暴力

加入 vis 数组,vis[i] 储存是否有长度大于等于2的连续子序列之和为 i

题目特别限制了 Memory Limit : 64MB

但又发现数组 a 中每个数都在 [1,n] 的范围内

所以数组 a b sum vis 都可以只开到 8000 稍大即可


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

int a[8050],b[8050],sum[8050];
bool vis[8050];
void solve()
{
    int n;
    scanf("%d",&n);
    sum[0]=0;
    memset(b,0,(n+5)*sizeof(int));
    memset(vis,false,sizeof vis);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[a[i]]++;
        sum[i]=sum[i-1]+a[i]; //前缀和
        for(int j=0;j<i-1;j++) //从0开始,因为长度大于等于2,所以到i-2过即可
        {
            if(sum[i]-sum[j]<=n) //防止越界(只要标记小于等于n的即可)
            {
                vis[sum[i]-sum[j]]=true;
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++) //处理到n过即可
    {
        if(vis[i])
            ans+=b[i]; //直接加上出现的个数
    }
    printf("%d
",ans);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}



1352 F - Binary String Reconstruction

Prob6


给定三个数 n0 n1 n2

要求构造一个 01 串,要求对于这个串的每个长度为 2 的连续子串,满足:

1出现0次的个数为 n0 ( "00" 出现 n0 次)

1出现1次的个数为 n1 ( "01" 或 "10" 出现 n1 次)

1出现2次的个数为 n2 ( "11" 出现 n2 次)


明显我们可以把同类的尽可能放在一起,方便处理

例如,如果 n0=5 ,就先构造出长度为 6 的全为 '0' 的字符串

然后开始 '0' '1' 交替

这里需要对 n1 的奇偶性进行讨论——

  如果 n1 是奇数,那么经过一系列 0101 变化后,最后一个字符会是 '1',就可以直接跟 n2 进行衔接,也就是在原来的基础上输出 n1 个交替的字符,再输出 n2 个 '1' 即可

  如果 n1 是偶数,那么经过一系列 0101 变化后,最后一个字符会是 '0',这样的话最后一个数字就不能和 n2 代表的 "11" 进行衔接,所以需要考虑把他与 0101 变化之中的某个 '1' 放在一起,所以也就是在原来的基础上输出 n1 - 1 个交替的字符先,再输出 n2 个 '1' ,最后补上一个 '0' 即可

因为题目保证存在这样的字符串,所以在 n0 和 n2 都不等于 0 时,n1也一定不为0(才能做到 "01" 衔接)

所以把 n1 等于 0 的情况分出来讨论即可


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

void solve()
{
    int n[3];
    scanf("%d%d%d",&n[0],&n[1],&n[2]);
    if(n[1]%2==1) //奇数,说明可以按照 n0 n1 n2 的顺序直接来
    {
        for(int i=0;i<=n[0];i++)
            putchar('0'); //先是 n0 +1 个'0'
        int d=1;
        for(int i=1;i<=n[1];i++)
        {
            putchar(d+'0'); //再是 n1 个"01"交替
            d=1-d; //01交替
        }
        for(int i=1;i<=n[2];i++)
            putchar('1'); //最后是 n2 个'1'
        putchar('
');
    }
    else if(n[1]%2==0&&n[1]!=0) //偶数且不为0,说明要把n2的'1'放在交替里
    {
        putchar('0');
        for(int i=1;i<=n[0];i++)
            putchar('0'); //先是 n0 +1 个'0'
        int d=1;
        for(int i=1;i<n[1];i++)
        {
            putchar(d+'0'); //再是 n1 -1 个"01"交替
            d=1-d;
        }
        for(int i=1;i<=n[2];i++)
            putchar('1'); //加入 n2 个'1'
        printf("0
"); //最后补上交替最后的那个'0'
    }
    else //如果n1为0,n0和n2只有一个不为0
    {
        if(n[0])
        {
            for(int i=0;i<=n[0];i++)
                putchar('0'); //直接输出 n0 +1 个'0'
            putchar('
');
        }
        if(n[2])
        {
            for(int i=0;i<=n[2];i++)
                putchar('1'); //直接输出 n2 +1 个'1'
            putchar('
');
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}



1352 G - Special Permutation

Prob7


要求构造出一个长度为 n 的全排列(即1~n的每个数字都用一次)

这个排列满足相邻的数字差值在 [2,4] 之间


明显,n=2和n=3是不存在这样的排列的

在n=4时,样例给出的 3 1 4 2 已经可以解决问题——

从小于等于 n 的最大奇数开始,每次递减 2 ,直到 3 1

至此,n 以内所有奇数就输出完了,接下来处理偶数

此时根据上面的例子可以得到接下来是 4 2,因为最大差值是4,所以可以紧接着 6 8 10 ... 直到把所有数字输出完为止

(当然反着来先看偶数再看奇数也没问题)

所以主要是最开始的找 小于等于 n 的最大奇数 ,直接使用 (n+1)/2*2-1 即可


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

void solve()
{
    int n,d;
    scanf("%d",&n);
    if(n<=3)
        puts("-1");
    else
    {
        d=(n+1)/2*2-1;
        for(;d>=1;d-=2)
            printf("%d ",d);
        printf("4 2 ");
        for(d=6;d<=n;d+=2)
            printf("%d ",d);
        putchar('
');
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}

原文地址:https://www.cnblogs.com/stelayuri/p/12861533.html