这个博客不再更新,新博客地址请戳
模考时间:2018年12月
希望这篇博客能够帮助到大家。
题目简单分析:
A
任务描述
在湘大xx奶茶店夏天推出了新的饮料价格为5元。
很多学生都要买饮料,每个学生一次只买一个。
然后给你人民币5元、10元或20元。
之后你给每个买了饮料的学生找零。
最初你这里没有钱(当第一个学生拿10元给你你就没办法找零钱)。
如果你能成功找零,返回true,否则返回false。
样例
输入:
5 5 5 10 20
输出:
true
思路:
温暖的签到题。
按照输入直接模拟收银过程便可。
记录一下手中当前有多少张5元,多少张10元便可。
①:收到5元。直接记录便可,因为不需要找零。
②:收到10元。由于要找零5元,那么看手中是否有5元的,然后相应的减一和加一便可。
③:收到20元。找零15元,可以找10+5,也可以5+5+5,但是我们通过生活经历可以知道一定要把整钱找出去,零钱留在手里最好,所以先判断有没有10+5,再判断有没有5+5+5。
#include
using namespace std;
int main(){
int cnt5=0,cnt10=0,cnt20=0;
int ans=1;
int a;
while(scanf("%d",&a)!=EOF){
if(a==5){
cnt5++;
}
else if(a==10){
if(!cnt5)ans=0;
else{
cnt5--;
cnt10++;
}
}
else{
if(cnt10&&cnt5){
cnt10--;cnt5--;
cnt20++;
}
else if(cnt5>=3){
cnt5-=3;
}
else{
ans=0;
}
}
}
if(ans)printf("true");
else printf("false");
return 0;
}
B
任务描述
工地有n块砖头需要搬运,但由于重量限制,每次只能搬1块或者2块,你能帮工地计算下能有多少种不同的搬运方法吗?
样例
比如n=3,1+1+1=1+2=2+1=3,共有3种不同的方法。
思路:
很裸的初中题:斐波那契数列。
如果不记得结论,可以自己在草稿纸上推出前几项的值,如果能够看出规律,就可以直接写了。
F(n) = F(n-1) + F(n-2) n>1
f(1) = F(0) = 1
#include
using namespace std;
typedef long long ll;
ll dp[1000];
int main(){
int n;
cin>>n;
dp[0]=1;
dp[1]=1;
for(int i=2;i<=n;i++)dp[i]=dp[i-1]+dp[i-2];
printf("%lld",dp[n]);
return 0;
}
C
任务描述
这里我们定义一个新的数:对于一个正整数x,再将x每个数位的平方和赋值给x,重复上一步,最后这个数等于1。
你需要写程序判断一个数符不符合这个定义。
如果无限循环但始终变不到1,则输出NO。
如果可以变为1,那么这个数符合定义则输出YES。
样例
19 就符合定义。
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
思路:
我们可以暴力模拟这个过程,因为一个数的平方和肯定是不会太大的,用不着几次就会降低到很小的数字。
这时,如果该数字变成了1,那么输出yes。如果它变成了之前出现过的数字,说明陷入了死循环,肯定是要不得的,这样就直接跳出循环,输出no。
#include
using namespace std;
int vis[1000000];
int ans=1;
void dfs(int x){
vis[x]=1;
int sum=0;
int xx=x;
while(xx){
sum+=(xx%10)*(xx%10);
xx/=10;
}
if(vis[sum])ans=0;
else dfs(sum);
}
int main(){
int x;scanf("%d",&x);
dfs(x);
if(vis[1])printf("YES");
else printf("NO");
return 0;
}
D unsolved
任务描述
工地有一个n升蓄水池,现在需要将它灌满水(不能溢出),当第i次灌水的时候,可以灌入1至num[i-1]升水。
问有多少种灌满水的方法?答案可能很大,答案对1e9+7取模。
• 1 <= n <= 10^6
• 1 <= num[i] <=10^6
样例
给出n=2,num=[2,2],返回2。
解释:
可以倒入2次1升的水,也可以在第1次倒入2升的水。
给出n=3,num=[3,2,1],返回4
解释:
方案一:第1次倒入3升的水。
方案二:第1次倒入1升的水,第2次倒入2升的水。
方案三:第1次倒入2升的水,第2次倒入1升的水。
方案四:第1次倒入1升的水,第2次倒入1升的水,第3次倒入1升的水。
思路:
对于这个毒瘤题表示恶心。
首先,题面描述有错误,然后数据范围应该是错的。
经过我的测试,n的范围是100,num[i]的范围也是100。
然后我写的动态规划是下面的代码,不清楚为什么会wrong answer。
如果有大佬能够看出错误,请务必指出,谢谢。
我的做法是这样的:
1.用 dp[ i ][ j ] 表示到达第i次灌水的时候,池子里有j升水的方案数。
2.那么,初始值 dp[ 0 ][ 0 ] 我们设为 1 ,表示一开始没有水的方案数为 1 。
3.然后 for 循环枚举 i 和 j ,我们想到,第 i 天的加水量范围是 [ 1, num[i] ],那么我们用 for 循环枚举这个增量 add 就好了,这三层循环的复杂度在题面数据范围下是爆炸的,但是经过测试,在我测的数据范围下是可以通过的。
4. dp[ i ][ j] += dp[ i-1 ][j - add],表示第 i 天如果加入 add 升水,那么蓄水池里有 j 升水的方案数,应该从 前一天有 j - add 升水的方案数转移得到。(注意数组越界)
5. 最后我们把所有 dp[ i ][ n ] 相加便是答案。
#include
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
ll dp[1005][1050];
int num[1005];
int main(){
memset(dp,0,sizeof dp);
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",num+i);
}
dp[0][0]=1;
int ans=0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
for(int add=1;add<=num[i];add++){
if(j-add>=0)dp[i][j]+=dp[i-1][j-add];
dp[i][j]%=mod;
}
}
ans+=dp[i][n];
ans%=mod;
}
printf("%lld",ans);
return 0;
}
E
任务描述
又快到了寒假时间,说到寒假,免不了出去玩耍,小蒋今天要去郊游,她想带点零食去,但是她的包包大小有限,所以她需要在n个零食中挑选若干零食装入包包,最多能装多满?假设包包的大小为m,每袋零食的大小为A[i]。
样例
如果有4个零食大小是[2, 3, 5, 7]。
如果包包的大小为11,可以选择[2, 3, 5]装入背包,最多可以装满10的空间。
如果包包的大小为12,可以选择[2, 3, 7]装入背包,最多可以装满12的空间。
测试说明
平台会对你编写的代码进行测试:
测试输入:
11
2 3 5 7
预期输出:
10
思路:
01背包问题的简化版本
由于我的代码写成一维滚动数组的形式,所以有个小细节,就是遍历的顺序从大到小。
核心思想是:
dp[ k ] 表示到达当前物品的时候,背包里装了重量为 k 的物品的情况存不存在。
枚举所有物品,到达第 i 个物品的时候,我们枚举“已装重量k”,如果在前面的物品中,我们得到“背包里装了重量为 k 的物品的情况存在”这一信息的话,那么 dp[ k + v[i]] =1 ,表示“到目前为止,背包里装了重量为 k + v[i] 的物品的情况存在”
最后看一下最大存在的重量便可。
#include
using namespace std;
int main(){
int m;cin>>m;
vector v;
int a;
while(scanf("%d",&a)!=EOF){
v.push_back(a);
}
sort(v.begin(),v.end());
vector dp;
dp.resize(m+10);
dp[0]=1;
int ans=0;
for(int i=0;i=0;k--){
if(dp[k]&&k+v[i]<=m){
dp[k+v[i]]=1;
ans=max(ans,k+v[i]);
}
}
}
printf("%d",ans);
return 0;
}
F
任务描述
小明他抛了n个骰子,抛出来之后显示的数是x1,x2,x3…xn;
令Z=x1+x2…+xn。(比如抛两个骰子 ,显示2,5。那么n=2,Z=7)
给定骰子个数n,计算出所有有几率出现的Z值以及他出现的可能性(几率)。
概率用double类型,保留6位小数。
编程要求
抛出n个骰子,抛出来之后显示的数是x1,x2,x3…xn;
令Z=x1+x2…+xn。
计算出所有Z值以及他出现的可能性(几率)。
测试说明
平台会对你编写的代码进行测试:
测试输入:1
预期输出:
1 0.166667
2 0.166667
3 0.166667
4 0.166667
5 0.166667
6 0.166667
思路:
首先我们知道,骰子有6个面,每次投掷每个面的概率都是0.166667。
我们直接模拟便可:
定义 i : pair( x , y ) 表示第 i 次投掷可以得到总和 x 的方案数 y 。
第1次:
(1,1) (2,1)(3,1)(4,1)(5,1)(6,1)
我们不妨按照这个过程模拟一下,就可以很轻松得到答案啦。
依旧是一个简单的状态转移过程,可以说是动态规划吧。
详细的不想说了,有兴趣看的自己看代码吧。
#include
using namespace std;
typedef long long ll;
const double eps = 1e-15;
map mp,mp2;
vector >ans;
int main(){
//freopen("a.out","w",stdout);
int n;cin>>n;
if(n==1){
for(ll i=1;i<=5;i++)printf("%lld 0.166667\n",i);
printf("%lld 0.166667",6);
return 0;
}
double all = pow(6,n);
for(int i=1;i<=6;i++)mp[i]=1;
for(int i=2;i<=n;i++){
mp2.clear();
for(auto p:mp){
for(int add=1;add<=6;add++){
mp2[p.first+add]+=mp[p.first];
}
}
mp.clear();
for(auto p:mp2)mp[p.first]=p.second;
}
for(auto p:mp){
if(p.first
评价:
1.总的来说,这套题的质量还行;
2.动态规划偏多,对难度的把控不是很到位;
3.数据范围如果不写清楚会造成很大影响,但是我们可以尝试二分范围的方式测试数据范围;