• 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分 暴力
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #define maxn 100010
    using namespace std;
    int t[maxn],v1[maxn],v2[maxn],a[maxn];
    int n,m,sum,ans;
    bool OK(int x){
        int i;
        for(i=x-n+1;i>=1;i-=n)
            if(!v2[i])return false;
        i+=n;
        if(i-1>0&&!v1[i-1])return false;
        return true;
    }
    int main(){
        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=1;i<=n;i++)t[i]=0;sum=0;
        for(int i=1;i<=min(n,m);i++){
            t[a[i]]++;
            if(t[a[i]]==2)sum++;
            if(!sum)v1[i]=1;
            else v1[i]=0;
        }
        if(!sum)v2[1]=1;else v2[1]=0;
        for(int i=n+1;i<=m;i++){
            t[a[i]]++;
            if(t[a[i]]==2)sum++;
            t[a[i-n]]--;
            if(t[a[i-n]]==1)sum--;
            if(!sum)v2[i-n+1]=1;
            else v2[i-n+1]=0;
        }
        for(int j=1;j<=n;j++)t[j]=0;sum=0;
        int j;
        for(j=m;j>=1;j--){
            t[a[j]]++;
            if(t[a[j]]>=2)break;
        }
        for(int i=m;i>max(0,m-n);i--){
            if(j<=i)
                if(OK(i))ans++;
        }
        if(ans)printf("%d
    ",((n>=m&&ans==m)?n:ans));
        else printf("0");
        return 0;
    }
    100分
  • 相关阅读:
    .NET框架设计—常被忽视的C#设计技巧
    判断网络是否链接
    ADO.NET入门教程(五) 细说数据库连接池
    爬虫selenium中截图
    爬虫极滑块验证思路
    Linux 磁盘分区、挂载
    linux中crontab任务调度
    第30课 操作符重载的概念
    第29课 类中的函数重载
    第28课 友元的尴尬能力
  • 原文地址:https://www.cnblogs.com/thmyl/p/7616940.html
Copyright © 2020-2023  润新知