zoukankan      html  css  js  c++  java
  • 第七届山东省省赛题解

    A - Julyed

    类型:

    水题

    题意:

    Julyed正在为她的大学英语六级考试做准备。她有N个字要记,但只剩M天了。如果她记不住这些话,她就不会通过大学英语六级考试。如果她不能通过大学英语六级考试,她就会不高兴。但如果她在某一天记得太多的话,她也会不开心。如果她不高兴,汤姆就会不高兴。所以她会在一天之内记住尽可能少的单词。为了快乐和快乐,在一天中,最多将会有多少个单词会被记住呢?

    题解:

    水题 N / 天数  上取整

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    using namespace std;
    int main()
    {
        int T;
        cin >> T;
        while(T--)
        {
            int a,b;
            cin >> a >> b;
            int ans = ceil(a * 1.0/ b * 1.0);
            cout << ans << endl;
        }
        return 0;
    }

    B - Fibonacci

    题意:

    给定一个整数N,判断N是否可以写成不连续的斐波那契数之和。若能输不能输出-1,若能输出 N = f1 + f2 + f3 + … + fn.

    题解:

    首先不存在-1的情况。齐肯多夫定理:任何正整数都可以唯一地表示成若干个不连续的斐波那契数之和。

    证明:

    数学归纳法,可以自行查找

    那么只需要打好斐波那契表,逆序遍历Fib数,存到输出数组里,最后按照格式逆序输出即可

    int Fib[50];
    int ans[50];
    void init()
    {
        Fib[1]=1,Fib[2]=2;
        for(int i=3;i<=43;i++)
            Fib[i]=Fib[i-1]+Fib[i-2];
    }
    int main()
    {
        init();
        int T;
        cin>>T;
        while(T--)
        {
            int n;
            cin>>n;
            int len=0,put=n;
            for(int i=43;i>=1;i--)
                if(n>=Fib[i])
                    ans[++len]=Fib[i],n-=Fib[i];
            cout<<put<<"="<<ans[len];
            for(int i=len-1;i>=1;i--)
                cout<<"+"<<ans[i];
            cout<<endl;
        }
    }

    C - Proxy

    题意:

    寻找给定起点和目标点的最短路上,与起点相连的编号最小的节点序号。类型:图论,思维

    题解:

    这是一道最短路问题。 要求有以下几点:

    ①求最短路,如果没有输出-1;
    ②输出最短路当中的距离起点最近的那个点
    ③存在多个最短路时,输出最小的那个点

    第一点套模版即可。
    第二点,我们记录路径往往最容易查询距离终点最近的那个点。所以我们可以建反向边,这样就可以查询距离起点最近得了。
    第三点,这是这道题的核心考点。 如果某点加上当前的路径长度刚好等于最短路的长度,那么说明存在两条最短路了,这时候比较当前点和原本终点的前一个点的大小,选择小的替换

    题型:

    图论

    代码:

    int INF = 1<<29;
    int mp[1010][1010];
    int n,m;
    int d[1010];
    int path[1010];
    bool vis[1010];
    void init(int n)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
            {
                if(i==j)
                    mp[i][j]=0;
                else
                    mp[i][j]=INF;
            }
    }
    
    void dijkstra()
    {
        int i,j,minn,v;
    
    
        for(i=0; i<n; i++)
        {
            vis[i]=0;
            d[i]=mp[n-1][i];
            if(mp[n-1][i]<INF)
                path[i]=0;
            else
                path[i]=-1;
        }
        path[n-1]=0;
        for(i=0; i<n; i++)
        {
            minn=INF;
            for(j=0; j<n; j++)
                if(!vis[j] && d[j]<minn)
                {
                    v=j;
                    minn=d[j];
                }
            vis[v]=1;
            for(j=0; j<n; j++)
                if(!vis[j] && d[j]>mp[v][j]+d[v])
                {
                    d[j]=mp[v][j]+d[v];
                    path[j]=v;
                }
                else
                {
                    if(!vis[j]&&d[j]==mp[v][j]+d[v])
                    {
                        path[j]=min(path[j],v);
                    }
                }
        }
    }
    int main()
    {
        int t,a,b,c;
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            n+=2;
            init(n);
            for(int i=0; i<m; i++)
            {
                cin>>a>>b>>c;
                mp[b][a]=c;
            }
            dijkstra();
            if(d[0]==INF)
            {
                cout<<"-1"<<endl;
            }
            else
            {
                cout<<path[0]<<endl;
            }
        }
    }

    D - Swiss-system tournament

    题意:

    给出2*n个人,每次第1个人和第2个人比赛,第3个人和第4个人比赛…进行r轮比赛,每轮比完赛都进行排名,求出最后第q名是谁。给出每个人的积分 s[i],每个人的能力a[i],能力大的获胜,获胜的加1分,输了的不加分。

    类型:

    思维 ,归并思想

    题解:

    这个题目用到了归并排序的思想,每轮比赛,把赢者放一组,输者放一组,这样单个数组也是有序的,然后进行合并。时间复杂度为0(2n*R)

    代码:

    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    struct node
    {
        int a,b;
        int index;
    };
    node ans[200005];
    node temp1[200005];
    node temp2[200005];
    
    bool cmp(node a,node b)
    {
        if(a.a==b.a)
            return a.index<b.index;
        return a.a>b.a;
    }
    int main()
    {
        int T;
        int n,r,q;
        int i,j,k,l;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d %d %d",&n,&r,&q);
            for(i=0; i<2*n; i++)
            {
                scanf("%d",&ans[i].a);
                ans[i].index=i+1;
            }
    
            for(i=0; i<2*n; i++)
                scanf("%d",&ans[i].b);
            sort(ans,ans+(2*n),cmp);
            for(i=0; i<r; i++)
            {
                int cnt1=0,cnt2=0;
                for(j=0; j<2*n; j+=2)
                {
                    if(ans[j].b > ans[j+1].b)
                    {
                        ans[j].a++;
                        temp1[cnt1++] = ans[j];
                        temp2[cnt2++] = ans[j+1];
                    }
                    else
                    {
                        ans[j+1].a++;
                        temp1[cnt1++] = ans[j+1];
                        temp2[cnt2++] = ans[j];
                    }
                }
                j=0;
                k=0;
                l=0;
                while(j<cnt1 && k<cnt2)
                {
                    if(temp1[j].a == temp2[k].a)
                    {
                        if(temp1[j].index < temp2[k].index)
                        {
                            ans[l++] = temp1[j];
                            j++;
                        }
                        else
                        {
                            ans[l++] = temp2[k];
                            k++;
                        }
                    }
                    else if(temp1[j].a > temp2[k].a)
                    {
                        ans[l++] = temp1[j];
                        j++;
                    }
                    else
                    {
                        ans[l++] = temp2[k];
                        k++;
                    }
                }
                while(j<cnt1)
                    ans[l++] = temp1[j++];
                while(k<cnt2)
                    ans[l++] = temp2[k++];
            }
            printf("%d
    ",ans[q-1].index);
        }
    
        return 0;
    }

      

    E - The Binding of Isaac

    题意:

    就是找有多少个位置满足只与‘#’有且仅有一条公共边

    题解:

    暴力,数据量100 坑点 就是所给区域的外围的区域也算,翻译的时候会看到。

    类型:

    搜索,不过数据量比较水,是个签到,不过背景很新。

    代码:

    #include<stdio.h>
    int main()
    {
        char map[105][105];
        int i,j,n,m,l,sum,k;
        scanf("%d",&l);
        while(l--)
        {
            k=0;
            sum=0;
            scanf("%d%d",&m,&n);
            getchar();
            for(i=0;i<105;i++)
                for(j=0;j<105;j++)
                    map[i][j]=0;
            for(i=1;i<=m;i++)
            {
                for(j=1;j<=n;j++)
                    scanf("%c",&map[i][j]);
                getchar();
            }
            for(i=1;i<=m;i++)
                for(j=1;j<=n;j++)
            {
                if(map[i][j]=='#')
                {
                    if(map[i+1][j]==0)
                        sum++;
                    if(map[i-1][j]==0)
                        sum++;
                    if(map[i][j+1]==0)
                        sum++;
                    if(map[i][j-1]==0)
                        sum++;
                }
                if(map[i][j]=='.')
                {
                    if(map[i+1][j]=='#')
                        k++;
                    if(map[i-1][j]=='#')
                        k++;
                    if(map[i][j+1]=='#')
                        k++;
                    if(map[i][j-1]=='#')
                        k++;
                    if(k==1)
                        sum++;
                    k=0;
                }
            }
            printf("%d
    ",sum);
        }
        return 0;
    }

    F - Feed the monkey

    真~不会

    G - Triple Nim

    题意:

    有一堆石子,一共有n个,把n个石子分成三堆,求有多少种分配的方式能够使得bob win?

    题解:

    算是两个题解吧。
    第一:非正式的,就是打表找规律。
    规律如下:
    如果 n 是 奇数,直接输出 0.
    如果是偶数,并且是 2 的某个次方,输出 0.
    否则统计二进制中 1 的个数。
    两个 1 答案为 1
    三个 1 答案为 4
    四个 1 答案为 13
    五个 1 答案为 40
    六个 1 答案为 121
    可以把答案单独开个数组 F[ N ] = F [ N -1 ] * 3 +1;

    第二:正式的,这就是个Nim博弈
    尼姆博弈是利用二进制的思想,那么本题也可以利用二进制的思想,可知,如果要使得Alice输并且Alice为先手,只需要使得三堆石子异或等于0 即可,首先共有n个石子,把n转化成二进制来表示,假设其中有k个1存在,如果要使得三堆石子异或为0,则在三堆石子数的二进制数的每位上1的个数都要是偶数位,又可知,在二进制中,高位的1是由低位进位而得到的,也就是说高位的1可以分解成两个低位的1,当n是奇数的时候,最低位为1且没有办法分解,所以输出0,所以当n为偶数的时候,就有(3^k - 3)/6个,减去3是去掉一个为0的情况,除6是应为本题求得是排列。

    题型:

    博弈

    代码1:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    long long int f[50];
    int main()
    {
        int T;
        cin>>T;
        f[1]=0;
        f[2]=1;
        for(int i=3;i<=49;i++)
            f[i]=f[i-1]*3+1;
        while(T--)
        {
            long long int n;
            cin>>n;
            if(n%2)
            {
                cout<<0<<endl;
            }
            else
            {
                long long int x=n;
                int num=0;
                while(x)
                {
                    if(x%2)
                        num++;
                    x/=2;
                }
    
                cout<<f[num]<<endl;
            }
        }
    }

    代码2:

    #include <bits/stdc++.h>  
      
    using namespace std;  
      
    int main()  
    {  
        int t;  
        scanf("%d",&t);  
        while(t--)  
        {  
            long long n;  
            cin>>n;  
            if(n%2)cout<<"0"<<endl;  
            else  
            {  
                int num=0;  
                while(n)  
                {  
                    if(n%2)num++;  
                    n=n/2;  
                }  
                long long ans=(pow(3,num)-3)/6;  
                cout<<ans<<endl;  
            }  
        }  
        return 0;  
    }  

    H - Memory Leak

    题意:

    内存泄漏是C/ c++中一个众所周知的bug。当一个字符串比预期的长时,它将访问下一个数组的内存,这将导致问题并泄漏一些信息。你可以看到一个简单的例子:

    如我们所见,如果输入字符串的长度等于或大于数组的极限长度,则额外的部分将不会被存储,下一个数组的信息将在输出时被泄漏。输出将停止,直到找到“”字符(字符串末尾的符号)。在这个问题中,程序永远不会有意外的结束,最后一个数组不会泄漏其他信息。
    提供的源代码如下:

    INPUT
    多个测试用例,第一行是整数T (T <= 20),表示测试用例的数量。
    每个测试用例的第一行包含一个非空字符串,即字符串的定义,格式化为“char s1[s1_len], s2[s2_len]…”。“char”是数组的类型,它永远不会改变。s1,s2……是数组的名称。s1_len s2_len…长度限制。如果没有出错,数组应该能够存储输入字符串和“”。不同数组的定义将用逗号和空格分开。长度限制为正,长度限制之和小于10000。
    然后,将会有几行字符串,其中包含两到三个部分。
    第一部分是“get”或“cout”,第二部分是字符串s,表示数组的名称。s将只包含小写字母和数字数字,并以字母开头。在一个例子中s是不同的。如果第一部分是“get”,那么将会有第三部分,一个字符串,该字符串应该被输入到数组s中,输入字符串的长度将小于1000,并且只包含可见的ASCII字符。“get”操作将重写数组,无论之前数组中是什么,然后在字符串后面添加“”。不同的部分被一个空间隔开。
    Case以“return 0”结尾;
    整个输入文件小于10MB。
    对于每个“cout”,您应该输出一行包含实际输出的内容,这意味着您应该考虑内存泄漏的问题。如果请求的数组为空,则应该输出空行。

    类型:

    大模拟题 ,字符串处理。还有对英语也是一种考验,很容易漏条件。

    题解:

    判每个数组的类型和长度,然后就检查有没有内存泄漏。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    struct node
    {
        int l,r;
    }e[11111];
    int top;
    char s[11111];
    char c[11111][1111];
    char op[11111];
    int main()
    {
        int T;
    
        scanf("%d",&T);
    
        while(T--)
        {
            memset(s,0,sizeof(s));
    
            int pos = 0;
    
            top = 0;
    
            scanf("%s",op);
    
            while(1)
            {
                scanf("%s",op);
    
                int len = strlen(op);
    
                int num = 0,i = 0;
    
                for(i = 0;i < len; i++)
                {
                    if(op[i] != '[')
                        c[top][i] = op[i];
                    else break;
                }
    
                c[top][i] = '';
    
                for(i++ ;i < len; i++)
                {
                    if(op[i] == ']') break;
                    num = num * 10 + op[i] -'0';
                }
    
                e[top].l = pos;
    
                e[top].r = pos+num;
    
                pos+=num;
    
                top++;
    
                char ss = getchar();
    
                if(ss == '
    ') break;
            }
            while(1)
            {
                scanf("%s",op);
    
                if(op[0] == 'r')
                {
                    scanf("%s",op);
    
                    break;
                }
    
                if(op[0] == 'c') 
                {
                    scanf("%s", op);
    
                    for(int i = 0;i < top; i++)
                    {
                        if(strcmp(op,c[i]) == 0)
                        {
                            for(int j = e[i].l ; j < pos; j++)
                            {
                                if(s[j] == '') break;
    
                                printf("%c",s[j]);
                            }
    
                            printf("
    ");
    
                            break;
                        }
                    }
                }
                else if(op[0] == 'g')
                {
                    scanf("%s",op);
    
                    for(int i = 0 ;i < top; i++)
                    {
                        if(strcmp(op,c[i]) == 0)
                        {
                            gets(op);
    
                            int len = strlen(op);
    
                            int k = 1,j;
    
                            for( j = e[i].l ; j < e[i].r && k < len; j++, k++)
                            {
                                s[j] = op[k];
                            }
    
                            if(j < e[i].r)
                            {
                                s[j] = '';
                            }
    
                            break;
                        }
                    }
                }
            }
        }
    
        return 0;
    }

    I - Rock Paper Scissors

    真~不会

    J - Execution of Paladin

    题意:

    先来说一下每个卡牌是什么意思,左上角写着10的那个牌叫“亡者归来”,作用是召唤7个死亡的鱼人,
    下面的四个鱼人从左到右分别是:
    寒光智者(攻2):作用是每个玩家抽两张牌。对这个题来说没什么用。
    鱼人领军(攻3);所有的其他鱼人的攻击力+2
    蓝鳃战士(攻2);冲锋(就是一上来就能打,其他的需要休息一回合。)
    老瞎眼(攻2):冲锋,并且场上每有一个其他鱼人,他的攻击力就+1.

    题解:

    算斩杀,就是看看这一回合能造成多少伤害,
    先算一共的鱼人个数,再算领军的数量,在分别算蓝鳃和老瞎眼的个数,因为这两种可以上来就打,
    伤害量 = 2 * 领军 + 蓝鳃 * 2 + 2 *领军 + (鱼人个数+2)* 老瞎眼。

    类型:

    模拟

    代码:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int main()
    {
        int T;
        cin >> T;
        char a[50];
        int o,b,c,m;
        while(T--)
        {
            int n,e;
            o = 0,b = 0,c = 0,m = 0;
            cin >> n >> e;
            getchar();
            for(int i = 1; i <= n; ++i)
            {
                gets(a);
                if(a[0] == 'O')
                    o++;
                if(a[0] == 'C')
                    c++;
                if(a[0] == 'M')
                    m++;
                if(a[0] == 'B')
                    b++;
            }
            int sha = o * (2 + 2 * m + n - 1) + b * (2 + 2 * m);
            if(sha >= e)
            {
                cout << "Mrghllghghllghg!" << endl;
            }
            else
            {
                cout << "Tell you a joke, the execution of Paladin." << endl;
            }
        }
        return 0;
    }

    K - Reversed Words

    题意:

    字符串反转

    题解:

    就是将每个单词进行转置。

    类型:

    字符串操作

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int M = 1e6;
    char a[M];
    char b[M];
    int main()
    {
        int T;
        cin >> T;
        getchar();
        while(T--)
        {
            char c;
            memset(a,0,sizeof(a));
            memset(b,0,sizeof(b));
            for(int i = 0;;++i)
            {
                scanf("%c",&a[i]);
                if(a[i] == 32)
                {
                    for(int j = i - 1; j >= 0;--j)
                    {
                        printf("%c",a[j]);
                    }
                    cout << ' ';
                    i = -1;
                }
                if(a[i] == '
    ')
                {
                    for(int j = i - 1; j >= 0; --j)
                    {
                        printf("%c",a[j]);
                    }
                    cout << endl;
                    break;
                }
            }
        }
    }

    L - Password

    真~不会

  • 相关阅读:
    Java--基础阶段--2Java基本语法-2.6数组
    Java--基础阶段--2Java基本语法-2.4运算符
    Java--基础阶段--2Java基本语法-2.3.5进制间转化
    Java--基础阶段--2Java基本语法-2.3.4原码/反码/补码
    Java--基础阶段--2Java基本语法-2.3.3ASCII码/Unicode编码/UTF-8
    Java--基础阶段--2Java基本语法-2.3.2整数/浮点/字符/布尔类型
    Java--基础阶段--2Java基本语法-2.3.1变量
    Java--基础阶段--2Java基本语法-2.2.2Java中的名称命名规范
    Java--基础阶段--2Java基本语法-2.2.1标识符
    Java--基础阶段--第4章: 面向对象编程(上)
  • 原文地址:https://www.cnblogs.com/aiguona/p/9172485.html
Copyright © 2011-2022 走看看