2017-10-1 清北刷题冲刺班a.m

Posted Soda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017-10-1 清北刷题冲刺班a.m相关的知识,希望对你有一定的参考价值。

位运算1

(bit)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

LYK拥有一个十进制的数N。它赋予了N一个新的意义:将N每一位都拆开来后再加起来就是N所拥有的价值。例如数字123拥有6的价值,数字999拥有27的价值。

假设数字N的价值是K,LYK想找到一个价值是K-1的数字,当然这个答案实在太多了,LYK想使得这个价值为K-1的数字尽可能大。

 

输入格式(bit.in)

    一个数N。

 

输出格式(bit.out)

一个数表示答案。你需要输出一个非负整数,且这个数不包含前导0。

 

输入样例1

199

 

输出样例1

198

 

输入样例2

1000

 

输出样例2

0

 

对于20%的数据n<=10

对于40%的数据n<=100

对于60%的数据n<=1000

对于100%的数据1<=n<=100000。

技术分享
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 10
int n,bit[maxn],len;
int main(){
    freopen("bit.in","r",stdin);freopen("bit.out","w",stdout);
    scanf("%d",&n);
    while(n){
        bit[++len]=n%10;
        n/=10;
    }
    int now=1;
    while(bit[now]==0)now++;
    bit[now]--;
    while(bit[len]==0&&len>=1)len--;
    if(len==0)printf("0");
    else
    for(int j=len;j>=1;j--)printf("%d",bit[j]);
    fclose(stdin);fclose(stdout);
    return 0;
}
100分

 

火柴棒

(stick)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

众所周知的是,火柴棒可以拼成各种各样的数字。具体可以看下图:

    通过2根火柴棒可以拼出数字“1”,通过5根火柴棒可以拼出数字“2”,以此类推。

    现在LYK拥有k根火柴棒,它想将这k根火柴棒恰好用完,并且想知道能拼出的最小和最大的数分别是多少。

 

输入格式(stick.in)

    一个数k。

 

输出格式(stick.out)

    两个数,表示最小的数和最大的数。注意这两个数字不能有前导0。

 

输入样例

15

 

输出样例

108 7111111

 

数据范围

对于30%的数据k<=10。

对于60%的数据k<=20。

对于100%的数据1<k<=100。

技术分享
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int now,anslen=0x7fffffff,ans[101],sum[10];
bool anspre;
struct node{
    int num,cost,cnt;
}q[10];
void dfs(int len,int res){
    if(len>anslen)return;
    if(res==0){
        bool flag=0;
        if(anslen>len)flag=1;
        if(q[6].cnt==len)return;
        anslen=len;
        int lennow=0,ansnow[101];
        for(int i=1;i<=7;i++)sum[i]=q[i].cnt;
        //for(int i=1;i<=7;i++)cout<<sum[i]<<"  ";
        for(int i=2;i<=7;i++){
            if(sum[i]){
                lennow=lennow+1;
                ansnow[lennow]=q[i].num,sum[i]--;
                break;
            }
        }
        for(int i=1;i<=7;i++)
            while(sum[i]){
                lennow=lennow+1;
                ansnow[lennow]=q[i].num,sum[i]--;
            }
        for(int i=1;i<=lennow;i++){
            if(ans[i]>ansnow[i]){
                flag=1;break;
            }
        }
        if(!anspre)flag=1;
        //cout<<anslen<<‘ ‘;cout<<endl;
        if(flag==1){
            for(int i=1;i<=anslen;i++)ans[i]=ansnow[i];
            anspre=1;
        }
        //for(int i=1;i<=anslen;i++)cout<<ansnow[i];cout<<endl;
        return;
    }
    for(int i=1;i<=7;i++){
        if(res-q[i].cost>=0){
            q[i].cnt++;
            dfs(len+1,res-q[i].cost);
            q[i].cnt--;
        }
    }
}
bool cmp(node x,node y){
    return x.num<y.num;
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("stick.in","r",stdin);freopen("stick.out","w",stdout);
    q[1].num=0,q[1].cost=6;
    q[2].num=1,q[2].cost=2;
    q[3].num=2,q[3].cost=5;
    q[4].num=4,q[4].cost=4;
    q[5].num=6,q[5].cost=6;
    q[6].num=7,q[6].cost=3;
    q[7].num=8,q[7].cost=7;
    scanf("%d",&now);
    dfs(0,now);
    for(int i=1;i<=anslen;i++)printf("%d",ans[i]);
    printf(" ");
    if(now%2==1){
        int num=(now-3)/2;
        printf("7");
        for(int i=1;i<=num;i++)printf("1");
    }
    else {
        int num=now/2;
        for(int i=1;i<=num;i++)printf("1");
    }
    fclose(stdin);fclose(stdout);
    return 0;
}
40分 暴力
技术分享
/*
    最大值直接特判一下,最小值用dp解决
    dp[i]表示i根火柴能拼出的最小的数字,枚举该数字末尾的一位是几
*/
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <set>
using namespace std;
long long dp[105];
int f[15],n;
int main()
{
    freopen("stick.in","r",stdin);
    freopen("stick.out","w",stdout);
    f[1]=2; f[2]=5; f[3]=5; f[4]=4; f[5]=5;
    f[6]=6; f[7]=3; f[8]=7; f[9]=6; f[0]=6;
    dp[2]=1; dp[3]=7; dp[4]=4; dp[5]=2; dp[6]=6;dp[7]=8; 
    for (int i=8; i<=100; i++)
    {
        dp[i]=dp[i-f[0]]*10;
      for (int j=0; j<=9; j++)
        if (dp[i-f[j]]!=0)
        dp[i]=min(dp[i],dp[i-f[j]]*10+j);
    }
    cin>>n;
    cout<<dp[n]<< ;
    if (n%2==1) {cout<<7; n-=3;}
    while (n){cout<<1; n-=2;}
    return 0;
}
100分 动态规划

 

听音乐

(music)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

LYK喜欢听音乐,总共有n首音乐,有m个时刻,每个时刻LYK会听其中一首音乐,第i个时刻会听第ai首音乐。它给自己定了一个规定,就是从听音乐开始,听的每连续n首音乐都是互不相同的。例如当n=3时,从听歌开始,123321就是一个合法的顺序(此时LYK听了两轮歌,分别是123和321,每一轮的歌都是互不相同的),而121323就是一个不合法的顺序(LYK也听了两轮歌,第一轮中121存在听了两次相同的歌)。我们现在只截取其中一个片段,也就是说并不知道LYK之前已经听了什么歌。因此121323也仍然可以是一个合法的顺序,因为LYK之前可能听过3,然后再听121323,此时LYK听了三轮歌,分别是312,132和3。

现在LYK将告诉你这m个时刻它听的是哪首歌。你需要求出LYK在听这m首歌之前可能听过的歌的不同方案总数(我们认为方案不同当且仅当之前听过的歌的数量不同)。LYK向你保证它之前听过的歌的数量是在0~n-1之间的。因此你输出的答案也应当是0~n中的某个整数(答案是0表示LYK记错了,没有一个合法的方案)。

 

输入格式(music.in)

    第一行两个数n,m。

    第二行m个数表示ai。

 

输出格式(music.out)

    一个数表示答案。

 

输入样例1

4 10

3 4 4 1 3 2 1 2 3 4

 

输出样例1

1

 

样例解释1:LYK之前一定只听过2首歌(12或者21),这样可以分成3部分分别是34,4132,1234,每一部分都没有出现相同的歌。对于其它情况均不满足条件。

 

输入样例2

6 6

6 5 4 3 2 1

 

输出样例2

6

 

样例解释2:LYK之前听过0~5首歌的任意几首都是有可能满足条件的。

 

 

数据范围

对于50%的数据n,m<=1000。

对于100%的数据1<=n,m<=100000,1<=ai<=n。

其中均匀分布着n<m以及n>=m的情况。

 

提示:

LYK知道这个题目很长,但为了便于理解已经加了很多注释了……建议没看懂的同学们再重新看一遍……

技术分享
#include<iostream>
#include<cstdio>
#define maxn 100010
using namespace std;
int n,m,a[maxn],ans;
bool vis[maxn];
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("music.in","r",stdin);freopen("music.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    for(int i=0;i<n;i++){//枚举之前听过的歌的数量 
        bool flag=0;
        for(int j=1;j<=n-i;j++){
            if(vis[a[j]]){
                flag=1;
                break;
            }
            vis[a[j]]=1;
        }
        for(int j=1;j<=n-i;j++)vis[a[j]]=0;
        if(flag)continue;
        for(int j=n-i+1;j<=m;j+=n){//区间起点 
            for(int k=j,l=1;k<=m&&l<=n;k++,l++){
                if(vis[a[k]]){
                    flag=1;
                    break;
                }
                vis[a[k]]=1;
            }
            for(int k=j,l=1;k<=m,l<=n;k++,l++)vis[a[k]]=0;
            if(flag)break;
        }
        if(!flag)ans++;
    }
    printf("%d",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
50分 暴力

 

以上是关于2017-10-1 清北刷题冲刺班a.m的主要内容,如果未能解决你的问题,请参考以下文章

2017-10-5 清北刷题冲刺班a.m

2017-10-3 清北刷题冲刺班a.m

2017-10-2 清北刷题冲刺班a.m

2017-10-4 清北刷题冲刺班a.m

2017-10-7 清北刷题冲刺班a.m

清北刷题冲刺 11-02 a.m