HHTC第十二届程序设计竞赛

HHTC第十二届程序设计竞赛

今天学校举办了一场关于程序设计的比赛!!!本人很菜,只能AC几个简单的题目,其他的难以突破!!!!

0x001 工资

Problem Description

地主将金币作为工资,发放给忠诚的长工。第一天,长工收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金币……;这种工资发放模式会一直这样延续下去:当连续N天每天收到N枚金币后,长工会在之后的连续N+1天里,每天收到N+1枚金币。
请计算在前K天里,长工一共获得了多少金币。

Input

输入文件只有1行,包含一个正整数K,表示发放金币的天数, 1 ≤ K ≤ 10,000。

Output

输出文件只有1行,包含一个正整数,即长工收到的金币数。

Sample Input

6

Sample Output

14

没有思路的思路:直接按照题意写就好,没有什么花里胡哨的东西!

AC代码:

#include <iostream>
using namespace std;
int main(){
    int n,sum;
    while(cin>>n){
        sum = 0;
        int x = 0,day = 0;
        for(int i = 1;day < n; i++){
            sum += i*i;
            x = i;
            day += i;
            if(day > n){
                sum -= (day - n) * i;
            }
        }

        cout<<sum<<endl;
    }
    return 0;
}

0x002 1的个数

Problem Description

二进制是计算技术中广泛采用的一种数制,二进制数据是用0和1两个数码来表示的数。平时我们常使用的是10进制数。现要你统计一个十进制整数对应二进制数1的个数。如8的二进制为1000,则1的个数为1.

Input

输入一个正整数n。

Output

输出正整数n对应二进制数1的个数。

Sample Input

10

Sample Output

2

没有思路的思路:这个题更加简单,就是二进制转化!

AC代码:

#include <iostream>
using namespace std;
int main(){
    int n,sum;
    while(cin>>n){
        sum = 0;
        while(n){
            if(n % 2 == 1)
                sum++;
            n /= 2;
        }
        cout<<sum<<endl;
    }
    return 0;
}

0x003 板上钉钉

Problem Description

木匠要为n块木板钉钉子。n块目前按编号从1到n依次排列成一条直线。
一开始,木匠先给1号和2号木板钉上钉子,然后跳过一个木板为4号钉上钉子,然后跳过两个木板为7号钉上钉子,依次类推,每一次都跳过前一次加一个木板,如果到达最后一个木板,则下一个木板为第一个木板。请问,是否所有的木板都至少钉上一个钉子?

Input

输入多组测试样例,每个测试样例包含正整数n(2≤n≤1,000,000,000)。

Output

对于每一个输入,若所有的木板都至少钉上一个钉子,输出Yes,否则输出No

Sample Input

6

Sample Output

No

没有思路的思路:这个题找规律!!因为相当于围成一个圈,一直循环下去!规律就是凡是2的n次方就是YES,自己可以去尝试!

AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <cstring>
#include <map>
using namespace std;

int main(){
    int n,sum;
    while(cin>>n){
        sum = 0;
        int x = n;
        while(n){
            sum++;
            n /= 2;
        }
        //cout<<pow(2,sum-1)<<endl;
        if(int(pow(2,sum-1)) == x){
            cout<<"Yes"<<endl;
        }else{
            cout<<"No"<<endl;
        }
    }
    return 0;
}

0x004 因子数

Problem Description

《权游》一直都很火,但是在第八季的时候,活了7季的Night King却抵不住正面一刀。随之Night King见到了上帝,上帝问了他一个问题,如果Night King回答正确就可以去天堂,反正则下地狱。你能帮Night King给出答案吗?
给定两个整数l和整数r,找出在区间[l,r]中所有数的的因子,统计出现次数最多的那个因子。如果有多个因子,则输出最小的因子。

Input

多组测试数据,每组一行,每行包括两个数l和r(2<=l<=r<=10^9);

Output

输出符合条件的最小的那个数(1除外);

Sample Input

17 27

Sample Output

2

没有思路的思路:这个题,数字给的很大,直接暴力肯定是不可能的,,,最后发现最小?不就是2最小而且最多吗?一样的时候另外做判断即可!

AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <cstring>
#include <map>
using namespace std;

int main(){
    int n,m,sum;
    while(cin>>n>>m){
        int flag = 1;
        if(n == m){
            for(int i=2;i <= sqrt(n);i++){
                if(n % i == 0){
                    cout<<i<<endl;
                    flag = 0;
                    break;
                }
            }
            if(flag == 1){
                cout<<n<<endl;
            }
        }else
        cout<<2<<endl;
    }
    return 0;
}

0x006 蛋糕

Problem Description

在一个N*M的迷宫中,小翔被随机的投放到一点,已知迷宫中有着各种各样的传送方式,w表示向上走一格,s表示向下走一格,a表示向左走一格,d表示向右走一格,o表示蛋糕,请问有多少个点可以让小翔最终走到蛋糕的位置。

Input

第一个输入N,M两个正整数(1≤n≤1000,1≤m≤1000)

接下来输入N行M列的迷宫。
Output

一个数,表示有几个点可以让小翔最终走到蛋糕位置。

Sample Input

5 5
ddddd
dsssd
ddoaa
wwwww
wwwww
1 1
d

Sample Output

19
0

没有思路的思路:这个题有很多人没做出来!我觉得奇怪,也有人说这样会超时,不过我就是过了,啊哈哈哈哈哈,其实也不难,就是一道简单的模拟题,注意一点,要标记一下,防止进入一个循环的圈子。

AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;

int n,m,sum;
char a[1005][1005];
int vis[1005][1005];
bool f(int i,int j){
    memset(vis,0,sizeof(vis));
    while(i < n && j < m && i >= 0 && j >= 0 && !vis[i][j]){
        if(a[i][j] == 'd'){
             vis[i][j] = 1;
            j += 1;
        }
        else if(a[i][j] == 's'){
            vis[i][j] = 1;
            i += 1;
        }
        else if(a[i][j] == 'w'){
            vis[i][j] = 1;
            i -= 1;
        }
        else if(a[i][j] == 'a'){
            vis[i][j] = 1;
            j -= 1;
        }
        if(a[i][j] == 'o')
            return true;
    }
    return false;
}
int main(){
    while(cin>>n>>m){
        getchar();
        sum = 0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                cin>>a[i][j];
            }
            getchar();
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(f(i,j))
                    sum++;
            }
        }
        cout<<sum<<endl;
    }
    return 0;
}

0x011 Sequential game

Problem Description

Sequential detector is a very important device in Hardware experiments. But is very difficult for many students such as HeroWei. In nearest days, his teacher Miss Fang let him simulate sequence detector. But there many sequence here ,and Miss Fang add the difficulty that when she give HeroWei a sequence and a string ,you must tell her how many string here in this sequence. But now Miss Fang simplified the problem for HeroWei, she just give Herowei a sequence and let HeroWei play a game with it.
When comes a character , it must compare with the rightmost one of sequence, if it’s the same with the coming characters ,the coming one just join the string. Most the right side. Otherwise all the characters in the sequence must change its value, 0 to 1 and 1 to 0,then the coming one add to its right side. Here is an example, if there is a sequence ‘110’ when comes a character 0,the sequence become ‘1100’ at last, if comes a character 1,the sequence become ‘0011’ at last.
It’s very difficult for HeroWei to play the game. Can you help him?

Input

Each line contains a composed by a string of 0s and 1s.the input is ended by EOF.

Output

For each given sequence you just play with this string as descripted above.Output a line contains two integers ,which are the number of 0s and 1s in the sequence after the game.

Sample Input

0
110
1111
1010

Sample Output

1 0
3 0
0 4
4 0

Tips
For example ,1010:  1->00->111->0000

没有思路的思路:这个题做不出来可能就是题目看不懂了,就拿样例来说吧,1010,一开始输入1,然后输入0,变成00,也就是输入0,前面的数与0不同就变成0,输入1,前面的数与1不同就变成1,这就好理解了,看最后一个数字是啥,这一串就由啥组成!!

AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <cstring>
#include <map>
using namespace std;

int main(){
    string s;
    while(cin>>s){
        if(s[s.size()-1] == '1'){
            cout<<0<<" "<<s.size()<<endl;
        }else{
            cout<<s.size()<<" "<<0<<endl;
        }
    }
    return 0;
}

下面是自己没做出来的题:

0x005 能量补充

Problem Description

有(N+1)个城市,0是起点N是终点,一运动员跑步从0 -> 1 - > 2… -> N,每跑一公里消耗1个单位的能量,运动员最多可以存储T单位能量,能量需要购买能量饮料才可以补充,一瓶能量饮料补充1个单位的能量。给出每个城市到下一个城市的距离D,以及当地的能量饮料的单价P,求跑完全程的最少花费。如果无法从起点到达终点输出-1。
例如D = {10, 9, 8}, P = {2, 1, 3},T = 15,最小花费为41,在0加上10个单位的能量,在1加满15个单位的能量,在2加2个单位的能量,走到终点时恰好用完所有能量,花费为10 * 2 + 15 * 1 + 2 * 3 = 41。

Input

输入多个样例;
第1行:2个数N, T中间用空格分隔,N + 1为城市的数量,T为油箱的容量(2 <= N <= 100000, 1 <= T <= 10^9)。
第2至N + 1行:每行2个数D[i], P[i],中间用空格分隔,分别表示到下一个城市的距离和当地的油价(1 <= D[i], P[i] <= 1000000)。

Output

输出跑完全程的最少花费。如果无法从起点到达终点输出-1。
提示:数据量较大,建议用long long

Sample Input

3 15
10 2
9 1
8 3

Sample Output

41

以为是动态规划,没看题,结果是贪心,,,,

题解代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
struct P
{
    LL int d;
    LL int p;
} a[100010];
LL ans,n,T,d,p;
LL st=1,ed=1,s;
int main()
{
    while(~scanf("%lld%lld",&n,&T))
    {
        ans=0;
        st=1;
        ed=1;
        int flag=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld%lld",&d,&p);
            s=0;
            if(d>T)
                flag=1;
            if(flag)
                continue;
            for(int i=st; i<ed; i++)
            {
                if(p>a[i].p)
                    s+=a[i].d;
                else
                    ed=i;
            }
            if(s<T)
            {
                a[ed].p=p;
                a[ed].d = T-s;
                ed++;
            }
            while(st<ed)
            {
                if(a[st].d<=d)
                {
                    ans += a[st].d*a[st].p;
                    d-=a[st].d;
                    st++;
                }
                else
                {
                    ans+=d*a[st].p;
                    a[st].d-=d;
                    d=0;
                }
                if(d<=0)
                    break;
            }
        }
        if(flag)
            printf("-1\n");
        else
            printf("%lld\n",ans);
    }

    return 0;
}

0x007 服务

Problem Description

现在在实验室中有n台服务器,每一台都能执行任务。每一台服务器上都有唯一的识别id(1…n)。
现在执行q个任务,接下来的第i行都包含三个整数:
t_i 表示任务到来的时刻
k_i 表示需要多少台服务器来完成它
d_i 表示完成此任务需要多少时间
所有的t_i都是不相同的。

为了执行第i个任务,你需要k_i个服务器在t_i时刻是空闲的。在这些服务器开始执行任务的时候,每个服务器所需要消耗的时长比d_i要长,时间的计算方式为t_i,t_i+1,…,t_i+d_i-1。在执行任务的时候,从所有空闲服务器中选择id最小的k_i个服务器。如果在t_i时刻没有空闲的服务器来执行这个任务,那么这个任务将会被放弃。

编写程序确定将执行哪些任务以及将忽略哪些任务。

Input

第一行包括两个正整数 n,q (1≤n≤100, 1≤q≤1e5) 表示n太服务器和任务。
接下来的q行每行包括三个整数,
第i行包括t_i,k_i,d_i (1≤ t_i ≤1e6, 1≤ k_i ≤ n, 1≤ d_i ≤ 1000)
任务按照时间顺序出现,在不同的时间内完成.

Output

输出q行,如果第i个任务能够被执行,显示第i个任务所需要的服务器id的总和,否则 显示-1。

Sample Input

4 3
1 3 2
2 2 1
3 4 3

Sample Output

6
-1
10

他们一直说这个题挺简单的,不过我题目都没看!!

题解代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
typedef long long LL;
LL ser[105], tmp[105];
///201132   201141
int main()
{
    int n, q, k, t, d;
    while(~scanf("%d %d",&n,&q))
    {
        memset(ser, 0, sizeof(ser));
        memset(tmp, 0, sizeof(tmp));
        for(int i = 1; i <= q; i++)
        {
            scanf("%d%d%d", &t, &k, &d);
            int cnt = 0, ans = 0;
            memcpy(tmp, ser, sizeof(tmp));
            for(int j = 1; j <= n && cnt < k; j++)
            {
                if(tmp[j] <= t)
                {
                    cnt++;
                    tmp[j] = t + d;
                    ans += j;
                }
            }
            if(cnt < k)
            {
                printf("-1\n");
            }
            else
            {
                memcpy(ser, tmp, sizeof(ser));
                printf("%d\n", ans);
            }
        }
    }

    return 0;
}

0x008 最大地雷区

Problem Description

在一个阴森森的夜晚,小翔走到了一大片地雷区,小翔不但不害怕,还勾引起了他学习的兴趣。
已知在一个M*N的区域分布着很多地雷,每一个坐标都代表一个方形区域,四边长均为1,地雷为"X",没有地雷的空地为"."。每一个地雷与其8个方向的其他地雷都是相连的都是相连的,所有相连的地雷组成一个地雷区。
小翔已经确定了一个地雷坐标点X,Y,要求出包含X,Y这一点的地雷区域的周长是多少。

Input

要求多组样例输入,第一行输入四个整数N,M,X,Y(1≤M≤20,1≤N≤20,1≤X≤M,1≤Y≤N);然后输入N行每行M个字符,字符均由'.'和'X'构成,行号从1开始编号。

Output

对于每组样例,输出一个数字,便是选中的地雷所在的地雷区域的周长。

Sample Input

2 2 1 1
XX
XX
5 5 2 2
..XXX
.XXX.
X....
.X...
....X

Sample Output

8
20

说明:对于样例2,右下角的X单独属于一个地雷区,其他的X属于一个地雷区。

这个题写了那么久,最后还是没能AC,有点可惜,关键是不知道周长是怎么来的!!!!

题解代码:

#include<bits/stdc++.h>
using namespace std;
int m,n,x,y,ans,pd[22][22],dx[8]={-1,-1,1,1,-1,0,0,1},dy[8]={-1,1,-1,1,0,-1,1,0};
//pd:判断这个方格有没有被访问过,dx和dy:搜索时的方向(0-3是四个角,4-7是上下左右)
char k[22][22];
void dfs(int a,int b)
{
    pd[a][b]=1;//标记这个方格已经被访问过
    for(int c=0;c<8;c++){
        int d=dx[c]+a,e=dy[c]+b;
        if(d>0&&d<=m&&e>0&&pd[d][e]==0&&k[d][e]=='X')dfs(d,e);//如果这个格子没出界,没被访问过并且显示的是'X',就访问这个格子
        if(c>3&&(d<=0||d>m||e<=0||e>n||k[d][e]!='X'))ans++;//如果方向是上下左右,并且出界了或者显示的不是'X',周长就要+1
    }
}
int main()
{
    while(~scanf("%d%d%d%d",&m,&n,&x,&y))
    {
        ans=0;
        memset(pd,0,sizeof(pd));
        memset(k,0,sizeof(k));
    for(int a=1;a<=m;a++)
        for(int b=1;b<=n;b++)
            cin>>k[a][b];
    dfs(x,y),cout<<ans<<endl;
    }
    return 0;
}

0x009 矩阵

Problem Description

在一个n*m的矩阵中,每一个坐标有一个整数,小翔要求矩阵的左上角走到右下角,只能向下走或者向右走,小翔本身的初始数字为1,小翔每走一个格子自己的数字便会乘以该坐标点中的数字,请问当小翔走到右下角后,自己的数据(mod)K可以有几种结果,并分别列出每种结果。
例如:给出一个2*2的矩阵:

5 6
8 3
小翔的初始数字为1,开始从左上角进入矩阵,走到右下角,有两种走法,得到的数字分别为 1563=90和1583=120。如果我们令K=7,
可求得最后结果为:1,6。

Input

第一行输入三个整数,分别为N,M,K (1 ≤ M,N,K ≤ 30),然后有N行,每行有M个数。

Output

第一行输出有多少种可能结果,一个数字输出
第二行分别输出所有的可能结果(升序输出)。第二行末尾有一个空格

Sample Input

2 2 7
5 6
8 3

Sample Output

2
1 6

这个题题解使用动态规划写的,我用的是dfs,直接超时,,,,,,,,,,

超时的错误代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
using namespace std;

map<int,int> mp;
int n,m,k;
int a[35][35];
int vis[35][35];
int d[2][2] = {0,1,1,0};

void dfs(int x,int y,int sum){
    if(x == n-1 && y == m-1){
        mp[sum%k]++;
        //cout<<sum<<endl;
        return ;
    }
    for(int i=0;i<2;i++){
        int xx = x + d[i][0];
        int yy = y + d[i][1];
        if(xx >= n || yy >= m || xx < 0 || yy < 0)
            continue;
        if(vis[xx][yy] == 0){
            vis[xx][yy] = 1;
            dfs(xx,yy,(sum * a[xx][yy])%k);
            vis[xx][yy] = 0;
        }
    }
}

int main(){
    while(cin>>n>>m>>k){
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                cin>>a[i][j];
            }
        }
        vis[0][0] = 1;
        dfs(0,0,a[0][0]);
        int flag = 0;
        for(int i=0;i<k;i++){
            if(mp[i] != 0 && flag == 0){
                cout<<i;
                flag = 1;
            }else if(mp[i] != 0 && flag){
                cout<<" "<<i<<endl;
            }
        }
    }
    return 0;
}

题解代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{
    //freopen("test.in","r",stdin);//设置 cin scanf 这些输入流都从 test.in中读取
    //freopen("test.out","w",stdout);//设置 cout printf 这些输出流都输出到 test.out里面去
    int n,m,k,a[101][101]={0},sum;
    bool f[101][101][100]={0};//f[i][j][l]表示在(i,j)是否会出现l。
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        memset(a,0,sizeof(a));
        memset(f,0,sizeof(f));
        sum=0;
       // cout<<n<<" "<<m<<" "<<k<<endl;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
            a[i][j]%=k;
            if(i==1&&j==1)//要注意,在(1,1) 的位置是一定会出现a[1][1]%k的
                f[i][j][a[i][j]]=1;
            for(int l=0;l<k;l++)//枚举前一步可能出现的值
                if(!f[i][j][l*a[i][j]%k])//如果该位置已经为 true,就不用再算了。
                    f[i][j][l*a[i][j]%k]=f[i-1][j][l]||f[i][j-1][l];//转移方程。这里的  l*a[i][j]%k表示从上一格走到这一格,乘上数值然后再膜 k 。即是当前格出现的一个数值
        }
    for(int i=0;i<k;i++)
        sum+=f[n][m][i];//算出右下角可能有几种数
    cout<<sum<<endl;
    for(int i=0;i<k;i++)
        if(f[n][m][i])
            cout<<i<<" ";//逐个输出
    cout<<endl;
    }
    return 0;
}

还有几个题,,目前还不知道正确的代码是啥~~先这样吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值