2019年5月9日考试解题报告
我的思考
考了个二百五......果然,**就该待在**桶里
总体来说这次考试还是比较简单的,最后一个题我都不知道为什么没过......还是太lj了啊
T1:多重背包裸题,无需任何装饰......
T2:求前缀和
T3:简单贪心,我却只有五十分
(感觉到这里这篇解题报告就应该结束了,似乎没啥好写的了qwq)
题解们
T1
题目描述
提供一个背包,它最多能负载重量为W的物品。
现在给出N种物品:对于第i类物品,一共有Ci件物品;对于每一件物品,重量为Wi,价值为Vi。
找出一种装载方式使得背包中的物品总价值最大。
输入格式(backpack.in)
第一行两个整数N,W,代表物品的种类与背包的总负重。
第2~N+1行,每行三个整数Wi, Vi, Ci,代表第i种物品的重量、价值与数量。
输出格式(backpack.out)
仅一行,一个整数V,代表最大的总价值。
样例输入
3 9
5 8 2
3 6 2
2 1 5
样例输出
14
数据范围与限制
(1<=N<=20, 0<=W<=1000)
(1<=Wi<=100, 0<=Vi<=100, 0<=Ci<=100)
思路
这就是一道多重背包的裸题,直接把模板打出来用就行了,这里我用了二进制转化
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 50010
#define MAXN 1001
#define ll long long
using namespace std;
inline int read() {
char c=getchar();
int x=0,f=1;
for(; !isdigit(c); c=getchar())if(c=='-')f=-1;
for(; isdigit(c); c=getchar())x=x*10+c-48;
return x*f;
}
ll f[N],v[MAXN],w[MAXN];
int main() {
freopen("backpack.in","r",stdin);
freopen("backpack.out","w",stdout);
int n,W,wi,vi,ci,tot=0;
n=read(),W=read();
for(int i=1; i<=n; ++i) {
wi=read(),vi=read(),ci=read();
for(int j=1;; j<<=1) {
if(ci<j) {
v[++tot]=wi*ci,w[tot]=vi*ci;
break;
}
v[++tot]=wi*j,w[tot]=vi*j,ci-=j;
}
}
for(int i=1; i<=tot; ++i) {
for(int j=W; j>=v[i]; --j)
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
cout<<f[W]<<'
';
fclose(stdin);
fclose(stdout);
return 0;
}
T2
题目描述
Alice与Bob在玩游戏:
Alice首先给出两个数(X)与(Y) ((X<=Y));
Bob则按顺序将(X,X+1,X+2,…,Y-1,Y)写成一个大数S。
Alice最后将S首尾相连,让其围成一个圈。
这时,Bob想知道,从S的开头出发,往后的第L位到第R位数字之和是多少。
输入格式(circulate.in)
第一行四个整数(X,Y,L,R),代表Alice的两个数字和Bob想要知道的第(L)位到第(R)位的数字之和。
输出格式(circulate.out)
仅一行,一个整数M,代表第L位到第R位的数字之和。
样例输入
10 11 4 12
样例输出
7
样例解释
Bob将数字写成一行大数(S = 1011);围成一个圈后,从第4位到第12位分别是(1,1,0,1,1,1,0,1,1),它们的和是(7).
数据范围与限制
对于50%的数据,L=1, X,Y,L,R<=1000;
对于100%的数据,S的长度不大于10000,X,Y,L,R<=100000000.
思路
我们可以先将它的每一位分解出来,然后求前缀和,因为是一个环,所以直接除以再加上取模就可以不消耗较多空间和较多的时间得到答案
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 1010
#define MAXN 10100
using namespace std;
inline int read() {
char c=getchar();
int x=0,f=1;
for(; !isdigit(c); c=getchar())if(c=='-')f=-1;
for(;isdigit(c); c=getchar())x=x*10+c-48;
return x*f;
}
int x,y,l,r;
int a[MAXN],s[MAXN],n=0,m,b[N];
int work(int x){
if(x==0)return 0;
int g=x/n;
int r=x%n;
return s[n]*g+s[r];
}
int main(){
//freopen("circulate.in","r",stdin);
//freopen("circulate.out","w",stdout);
x=read(),y=read(),l=read(),r=read();
for(int i=x;i<=y;i++){
m=0;
int tmp=i;
while(tmp!=0)b[++m]=tmp%10,tmp/=10;
for(int j=m;j!=0;j--)a[++n]=b[j];
}
for(int i=1;i<=n;i++){
s[i]=s[i-1]+a[i];//求前缀和
}
int lefted=work(l-1);
int righted=work(r);
cout<<righted-lefted<<"
";
fclose(stdin);
fclose(stdout);
return 0;
}
T3
题目描述
Cindy和Dan在玩一个游戏。
一开始Cindy想出了N个数,接着她把这N个数全部给了Dan。
Dan得到这组数后,它会挑出3个数(如果不足3个则全部挑出)。Dan会把这几个数加起来变成一个数,然后再把这个数与剩下的数再放到一起。Dan会一直这样做,直到最后只剩下一个数。
Cindy则会在旁边记下每次Dan得到的数,她把这些数加起来,作为本次游戏的得分。她想知道,对于一组数,Dan能得到的最大的得分是多少?
输入格式
第一行一个正整数N,代表这组数的个数;
第二行N个正整数,代表这N个整数。
输出格式
一行一个整数,代表可能的最大得分。
样例输入(merge.in)
4
3 1 5 6
样例输出(merge.out)
29
样例解释
Dan可以首先把(3,5,6)这三个数先合并起来,得到3 + 5 +6 = 14;接着他把剩下的两个数再合起来,得到1+14=15.这样,总得分是最大的 14 + 15 = 29.
数据范围与限制
对于50%的数据,N<=10
对于100%的数据,N<=1000,所有数不大于1000
思路
这题还是比较简单的,可惜我还是挂分了......
排序从大到小找最大的一起加就行了
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<cstdlib>
#include<map>
#include<set>
#include<cstring>
#include<string>
using namespace std;
inline int read() {
char c=getchar();
int x=0,f=1;
for(; !isdigit(c); c=getchar())if(c=='-')f=-1;
for(; isdigit(c); c=getchar())x=x*10+c-48;
return x*f;
}
int n;
int a[1001];
bool cmp(int a,int b) {
return a>b;
}
int main() {
freopen("merge.in","r",stdin);
freopen("merge.out","w",stdout);
n=read();
for(int i=1; i<=n; ++i)a[i]=read();
sort(a+1,a+1+n,cmp);
long long ans = 0;
long long now = a[1];
for(int i=2; i<=n; i+=2) {
now+=a[i]+a[i+1];
ans+=now;
}
printf("%d
",ans);
fclose(stdin);
fclose(stdout);
return 0;
}