zoukankan      html  css  js  c++  java
  • 2017北京国庆刷题Day1 morning

    期望得分:100+100+100=300

    实际得分:100+100+70=270

    T1位运算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。

    最后一个非零数-1

    #include<cstdio>
    using namespace std;
    int num[7],bit[7],ans[7];
    int main()
    {
        freopen("bit.in","r",stdin);
        freopen("bit.out","w",stdout);
        int n,len=0;
        scanf("%d",&n);
        bit[0]=1; for(int i=1;i<7;i++) bit[i]=bit[i-1]*10;
        while(n) num[len++]=n%10,n/=10;
        bool ok=false;
        for(int i=0;i<len;i++) 
        {
            ans[i]=num[i];
            if(!ok && ans[i]) ans[i]--,ok=true;
        }
        int out=0;
        for(int i=0;i<len;i++) out+=ans[i]*bit[i];
        printf("%d",out);
        return 0;
    }
    View Code

    T2火柴棒 (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。

    最大:

    k=偶数,k/2个1

    k=奇数,1个7和(k-1)/2个1、

    最小:

    dp[i][j] j根火柴棒拼成的最小的i位数

    其实第一维没有用

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int use[8]={-1,-1,1,7,4,2,0,8};
    int k;
    long long dp[16][101];
    void out(long long x)
    {
        if(x/10) out(x/10);
        putchar(x%10+'0');
    }
    void solve_min()
    {
        if(k==6) { printf("0"); return; }
        int len=k/7+1;
        for(int i=2;i<8;i++) dp[1][i]=use[i];
        dp[1][6]=6;
        if(dp[1][k]) { out(dp[1][k]); return;}
        for(int i=2;i<=len;i++)
        {
            for(int j=1;j<=k;j++)
                for(int l=2;l<=7;l++)
                {
                    if(j-l<=1) continue;
                    if(!dp[i-1][j-l]) continue;
                    if(!dp[i][j]) dp[i][j]=dp[i-1][j-l]*10+use[l];
                    else dp[i][j]=min(dp[i][j],dp[i-1][j-l]*10+use[l]);
                }
            if(dp[i][k]) { out(dp[i][k]); return; }
        }    
    }
    void solve_max()
    {
        int len=k/2;
        if(k&1)
        {
            printf("7");
            for(int i=1;i<len;i++) printf("1");
        }
        else 
        {
            for(int i=1;i<=len;i++) printf("1");
        }
    }
    int main()
    {
        freopen("stick.in","r",stdin);
        freopen("stick.out","w",stdout);
        scanf("%d",&k);
        solve_min();
        printf(" ");
        solve_max();
    }
    View Code

    T3听音乐(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的情况。

    预处理每个位置往后没有重复能扩展到的最远位置

    然后枚举之前听过i首歌

    整个序列分为三部分,最前面不完整部分、中间完整几段、最后面不完整部分

    枚举每一段的左端点,如果他能向右扩展的部分>=这一段的右端点,说明这是合法的一段,继续下一段

    如果每一段都合法,那i就合法

    时间复杂度:n/1+n/2+n/3+……≈nlogn

    30分丢分原因:判断最前面不完整部分时,枚举了,这样复杂度就多加了n*(n-1)/2

    只要判断1是否能扩展到n-i即可

    #include<cstdio>
    #include<iostream>
    #define N 100002
    using namespace std;
    int n,m;
    int a[N],suf[N];
    bool vis[N],t=true;
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    void pre()
    {
        int r=m; vis[a[m]]=1; suf[m]=m;
        for(int i=m-1;i;i--)
        {
            if(!vis[a[i]]) suf[i]=r,vis[a[i]]=true;
            else
            {
                while(r>i)
                {    
                    if(a[r]==a[i]) { r--;break; }
                    vis[a[r--]]=false;
                }
                suf[i]=r;
            }
        }
        for(int i=1;i<=m&&t;i++)
            if(suf[i]<m)  t=false;
    }
    bool check(int x)
    {
        int first=0;
        if(x)
        {
            first=n-x;
            if(suf[1]<first) return false;
        }
        int r=first;
        for(int i=first+1;i<=m;i+=n)
        {
            r=min(m,r+n);
            if(suf[i]<r) return false;
        }
        return true;
    }
    int main()
    {
        freopen("music.in","r",stdin);
        freopen("music.out","w",stdout);
        read(n); read(m);
        for(int i=1;i<=m;i++) read(a[i]);
        pre();
        int ans=0;
        for(int i=0;i<n;i++) 
            if(n-i>m) ans+=t;
            else ans+=check(i);
        printf("%d",ans);    
    }
    View Code
  • 相关阅读:
    List<int>转化为逗号链接的字符串
    分页的总页数算法
    高性能SQLServer分页语句
    webconfig中的&符号问题解决
    检测SQLServer复制订阅进度
    jQuery自定义数组操作类(类似于List集合的增删改查)
    解决jquery绑定click事件出现点击一次执行两次问题
    IdentityServer4登陆中心
    AES加密解密通用版Object-C / C# / JAVA
    T-SQL 基本语法
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7617072.html
Copyright © 2011-2022 走看看