buct2018年程序设计实训作业一部分题目解答

背包题请拉到最后
问题 A: 不同的数字(easy)

题目描述
对于一个长度为n的数组a_1,a_2,...,a_n
你将会得到m次询问,每次询问给出l,r,你需要计算出a_l,a_(l+1),...,a_r中有多少个不同的数字
如1,2,2,3,3中有3个不同的数字,分别是1,2,3
输入
输入第一行两个整数n(1<=n<=100),代表数组长度,m(1<=m<=100),代表询问个数
第二行有n个数字,代表给定的数组.(1<=a_i<=1e6)
接下来m行,每行给出一个l,r,代表询问.(1<=l<=r<=n)
输出
对于每个询问输出一行,每行一个整数,代表区间内不同数字的个数.

样例输入
5 3
1 1 2 1 3
1 5
2 4
3 5
样例输出
3
2
3 

用一个数组记录数据,每次查询可以通过桶排达成0n的时间复杂度,对于本体时间足够了(水题)

#include<bits/stdc++.h>
using namespace std;
int a[105],b[1000005];
int main()
{
    int n,m;memset(b,0,sizeof(b));
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    cin>>a[i];
    while(m--)
    {
        int l,r;
        cin>>l>>r;
        int cnt=r-l+1;

        for(int i=l;i<=r;i++)
        if(b[a[i]]==1)cnt--;
        else b[a[i]]=1;
        cout<<cnt<<endl;
        for(int i=l;i<=r;i++)
        b[a[i]]=0;
    }
}

问题 C: 简单的数列问题

题目描述
有这么一个数列g,g[i]=g[i-1]+i,g[1]=1
这个数列的前几项依次是 1 3 6
现在有m个询问,每个询问给出一个a,你需要判断a是否存在于这个数列中
输入
第一行给出一个m,(m<=1e5),代表询问的次数
接下来m行每行一个整数a,(a<=1e9)
输出
对于每个询问输出"YE5"或者"N0"(不含引号),当a存在于数列g中时,输出"YE5",否则输出"N0"
每次输出占一行
样例输入
6
1
2
3
4
5
6
样例输出
YE5
N0
YE5
N0
N0
YE5

数列为1+2+3。。。即n(n+1)/2。对于给定的数字乘二之后便是n(n+1)。由于对整形求根之后会省略小数,所以求根得到n。然后判定n(n+1)是否等于原数乘二即可。
还有,输出的N0和YE5。结尾分别是0和5。

#include<bits/stdc++.h>
using namespace std;
long long k;
int main()
{
    int m;
    scanf("%d",&m);
    while(m--)
    {
        scanf("%lld",&k);
        k<<=1;
        long long t=sqrt(k);
        if(t*(t+1)==k)printf("YE5\n");
        else printf("N0\n");
    }
}

问题 D: 盘旋矩阵

题目描述
n阶盘旋矩阵是由前n^2个自然数从最后一行第一列依次盘旋而上形成的矩阵
一个4阶盘旋矩阵如下
16 15 14 13
 9 10 11 12
 8  7  6  5
 1  2  3  4
 3*3的盘旋矩阵如下
7 8 9
6 5 4
1 2 3
现在给出一个n,你一定能够很轻松写出一个程序输出每一行的和,但是充满恶意的出题人希望你能够写出一个程序输出每一列的和
输入
输入第一行一个整数T(1<=T<=50),代表测试组数
接下来T行,每行一个数n(1<=n<=200000)
保证所有n的和<=1000000
输出
输出T行,每行n个整数,代表n阶矩阵第一列到第n列每列的和
样例输入
2
3
4
样例输出
14 15 16
34 34 34 34

女生赛原题。具体。。。第一列的数字很容易求出来。然后如果n为偶数每一列的数字都一样,奇数的话每一列加一即可

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long k;int t;
    cin>>t;
    while(t--)
    {
        cin>>k;
        long long sum=0;
        for(long long j=0;j<k;j++)
        if(j&1)sum+=k*(j+1);
                else sum+=k*j+1;//求出第一列
        for(long long i=0;i<k;i++)
        cout<<sum+(k&1?i:0)<<' ';//根据奇偶输出
        cout<<endl;

    }
}

问题 E: TYVJ 1005 采药

题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”  如果你是辰辰,你能完成这个任务吗?

输入
输入第一行有两个整数T1  < =  T  < =  1000)和M(1  < =  M  < =  100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1100之间(包括1100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出
输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

样例输入
70 3
71 100
69 1
1 2
样例输出
3
提示
对于30%的数据,M  < =  10;对于全部的数据,M  < =  100

裸背包。方程只需要考虑时间。

#include<bits/stdc++.h>
using namespace std;
int a[1005];
struct yao{
    int c,v;
}b[105];
int main()
{
    memset(a,0,sizeof(a));
    int t,m;
    cin>>t>>m;
    for(int i=0;i<m;i++)
    {
        cin>>b[i].c>>b[i].v;
        for(int j=t;j>=b[i].c;j--)
        a[j]=max(a[j],a[j-b[i].c]+b[i].v);
    }
    cout<<a[t]<<endl;    
}

后面那几道也是背包。哦,dp。

问题 F: TYVJ 1011 传纸条

题目描述
小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个mn列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。 在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。 还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。
输入
输入文件message.in的第一行有2个用空格隔开的整数mn,表示班里有mn列(1< =m,n< =50)。 接下来的m行是一个m*n的矩阵,矩阵中第ij列的整数表示坐在第ij列的学生的好心程度。每行的n个整数之间用空格隔开。
输出
输出文件message.out共一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。
样例输入
3 3
0 3 9
2 8 5
5 7 0
样例输出
34
提示
30%的数据满足:1< =m,n< =10  
100%的数据满足:1< =m,n< =50

忽略文件输入输出。我突然不想讲怎么打了。。。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[55][55],b[110][55][55];
    memset(b,0,sizeof(b));
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        cin>>a[i][j];
    }
    for(int k=1;k<=n+m;k++)
    for(int i=1;i<=k;i++)
    for(int j=1;j<=k;j++)
    {
        int OvO=b[k-1][i-1][j-1];
        OvO=max(OvO,b[k-1][i-1][j]);
        OvO=max(OvO,b[k-1][i][j-1]);
        OvO=max(OvO,b[k-1][i][j]);
        if(i==j)b[k][i][j]=OvO+a[k-i+1][i];
        else b[k][i][j]=OvO+a[k-i+1][i]+a[k-j+1][j];
    }
    cout<<b[n+m][m][m];
    return 0;
}

问题 G: TYVJ 1013 找啊找啊找GF

题目描述
" 找啊找啊找GF,找到一个好GF,吃顿饭啊拉拉手,你是我的好GF.再见." " 诶,别再见啊..." 七夕...七夕...七夕这个日子,对于sqybi这种单身的菜鸟来说是多么的痛苦...虽然他听着这首叫做" 找啊找啊找GF" 的歌,他还是很痛苦.为了避免这种痛苦,sqybi决定要给自己找点事情干.他去找到了七夕模拟赛的负责人zmc  MM,让她给自己一个出题的任务.经过几天的死缠烂打,zmc  MM终于同意了. 但是,拿到这个任务的sqybi发现,原来出题比单身更让人感到无聊-_-....所以,他决定了,要在出题的同时去办另一件能够使自己不无聊的事情--给自己找GF. sqybi现在看中了n个MM,我们不妨把她们编号1到n.请MM吃饭是要花钱的,我们假设请i号MM吃饭要花rmb[i]块大洋.而希望骗MM当自己GF是要费人品的,我们假设请第i号MM吃饭试图让她当自己GF的行为(不妨称作泡该MM)要耗费rp[i]的人品.而对于每一个MM来说,sqybi都有一个对应的搞定她的时间,对于第i个MM来说叫做time[i].  sqybi保证自己有足够的魅力用time[i]的时间搞定第i个MM^_^. sqybi希望搞到尽量多的MM当自己的GF,这点是毋庸置疑的.但他不希望为此花费太多的时间(毕竟七夕赛的题目还没出),所以他希望在保证搞到MM数量最多的情况下花费的总时间最少. sqybi现在有m块大洋,他也通过一段时间的努力攒到了r的人品(这次为模拟赛出题也攒rp哦~~).他凭借这些大洋和人品可以泡到一些MM.他想知道,自己泡到最多的MM花费的最少时间是多少. 注意sqybi在一个时刻只能去泡一个MM--如果同时泡两个或以上的MM的话,她们会打起来的...
输入
输入的第一行是n,表示sqybi看中的MM数量.接下来有n行,依次表示编号为1,  2,  3,  ...,  n的一个MM的信息.每行表示一个MM的信息,有三个整数:rmb,  rp和time.最后一行有两个整数,分别为m和r.
输出
你只需要输出一行,其中有一个整数,表示sqybi在保证MM数量的情况下花费的最少总时间是多少.
样例输入
4
1 2 5
2 1 6
2 2 2
2 2 3
5 5
样例输出
13
提示
数据规模
对于20%数据,1< =n< =10;
对于100%数据,1< =rmb< =100,1< =rp< =100,1< =time< =1000;
对于100%数据,1< =m< =100,1< =r< =100,1< =n< =100.

Hint
sqybi说:如果题目里说的都是真的就好了...
sqybi还说,如果他没有能力泡到任何一个MM,那么他就不消耗时间了(也就是消耗的时间为0),他要用这些时间出七夕比赛的题来攒rp...

出题人
sqybi  GG

显然又不是原创题。单身狗受到巨额暴击。背包。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[105],m,r,b[105],c[105],n,dfs[105][105],t[105][105];
    cin>>n;
    memset(dfs,0,sizeof(dfs));
    memset(t,0,sizeof(t));
    for(int i=0;i<n;i++)
    cin>>a[i]>>b[i]>>c[i];
    cin>>m>>r;
    for(int i=0;i<n;i++)
    for(int j=m;j>=a[i];j--)
    for(int k=r;k>=b[i];k--)
    {
        if(dfs[j-a[i]][k-b[i]]>=dfs[j][k])
        {
            dfs[j][k]=dfs[j-a[i]][k-b[i]]+1;
            t[j][k]=t[j-a[i]][k-b[i]]+c[i];
        }
        else if(dfs[j-a[i]][k-b[i]]==dfs[j][k]-1)
        {
            t[j][k]=min(t[j][k],c[i]+t[j-a[i]][k-b[i]]);
        }
    }
    cout<<t[m][r];
}

问题 H: 买大米

题目描述
如果你现在有n元现金,你要用这n元现金去买大米,但市场上有m种大米,每种大米都是袋装的,其价格、重量都有可能不同,并且你只能整袋购买。你要如何才能用这有限的资购买到最多的大米呢?

输入
输入数据首先包含一个正整数T,表示有T组测试用例,每组测试用例的第一行是两个整数nm(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示大米每袋的价格、每袋的重量以及对应种类大米的袋数。

输出
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。

样例输入
1
8 2
2 100 4
4 100 2
样例输出
400

裸背包。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    int a[105];
    while(t--)
    {
        memset(a,0,sizeof(a));
        int n,m;
        scanf("%d%d",&n,&m);
        int r,b,q;
        while(m--)
        {

            scanf("%d%d%d",&r,&b,&q);
            for(int i=n;i>=0;i--)
            for(int j=1;j<=q&&j*r<=i;j++)

            {
                a[i]=max(a[i],a[i-j*r]+j*b);
            }
        }
        cout<<a[n]<<endl;
    //  for(int i=0;i<=8;i++)cout<<a[i]<<' ';
    }
}

问题 J: the 1s

题目描述
Given any integer 0 <= n <= 10000 not divisible by 2 or 5, some multiple of n is a number which in decimal notation is a sequence of 1's. How many digits are in the smallest such a multiple of n?

输入
Each line contains a number n.

输出
Output the number of digits of the smallest multiple of n.For example,111 is the smallest multiple of 3, so when n equals 3, the result is 3

样例输入
3 
7 
9901
样例输出
3
6
12

不说了,引用一个博客。https://blog.csdn.net/onepiece_only/article/details/52802678

总结

突然发现我懒得讲解。。。本次题目主要为裸背包题目。背包题目主要参考就是背包九讲。这个随便一搜便有结果。什么?懒得搜索?我帮你搜索了。https://blog.csdn.net/stack_queue/article/details/53544109

懒癌触发中。。。真心不想打字。有时间再补充吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值