ACdream DP专题训练
2015-07-26 17:15
363 查看
A - 小彭玉的扫荡食堂计划
Time Limit: 20000/10000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Problem Description
哗啦啦村的食堂很奇怪,就是如果这个饭卡所剩金额低于5元的话,这个饭卡就不能刷了。也就是说,只要这个饭卡金额大于等于5元,就可以随便刷~
有一天,小彭玉看了看哗啦啦食堂的饭,“哇,好好吃!我要全部都买下来!”
但是小彭玉并没有那么多钱,于是他准备充分利用自己的钱,去买这些食物!
请问最后小彭玉的饭卡余额最少能到多少?
Input
多组测试数据(最多100组)第一行 n,表示有n个菜
第二行 接下来n个数字,a[i]表示第i道菜多少钱
第三行 一个数m,表示小彭玉的饭卡,一开始有m元
1<=n<=1000,1<=a[i]<=10000,1<=m<=10000
Output
输出一个整数,表示最后饭卡显示的金额数
Sample Input
1 10000 6 10 1 2 3 2 1 1 2 3 2 1 50
Sample Output
-9994 32
解题思路:
由于饭卡小于5元就不能使用了,但是没规定5元以上不能刷超过的多少钱的东西,所以就算是负数也没关系(题目说随便刷)。所以我们可以枚举数组中的最大值,然后把输入当前总的钱数-5就是扣掉最大值之后能取到的最大值,很显然是个背包问题,套一下01背包的DP就能出来了。
AC代码:
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxn = 10100; int dp[maxn]; int a[maxn]; int main() { int m; int total; int res; int i,j; int Max; while(cin>>m) { memset(dp,0,sizeof(dp)); for(i=0;i<m;i++) { cin>>a[i]; } cin>>total; Max = a[0]; for(i=1;i<m;i++) { if(a[i] > Max) { Max = a[i]; } } //cout<<Max<<endl; bool flag = false; if(total < 5) { cout<<total<<endl; continue; } else { for(i=0;i<m;i++) { if(a[i] == Max && !flag) { flag = true; continue; } else { for(j=total - 5;j>=a[i];j--) //只要大于5就可以再买那个最大的 { if(dp[j] < dp[j-a[i]] + a[i]) { dp[j] = dp[j-a[i]] + a[i]; } } } } } cout<<total - Max - dp[total - 5]<<endl; } return 0; }
E - 喵哈哈的日常选数问题
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Problem Description
喵哈哈村子的TTT同学比较怪,他非常讨厌一类数字,是哪种呢?就是讨厌那些含有37或者4的数
比如 21379,123485,12379。
但是他并不讨厌928357这个数,因为他即不包含37,也没有4。
现在你[L,R]的区间,问你在这个区间中,最多能够选出多少个TTT同学不讨厌的数呢?
Input
输入两个整数,表示L和R1 <= L <= R <= 2000000000 。
Output
输出一个整数,表示选出的数的个数
Sample Input
1 10
Sample Output
9
解题思路:数位DP问题,数位DP这个链接讲得挺清楚的,ACdream的数据有点小弱,第一次高位和低位写反,竟然还能AC。
AC代码:
#include <iostream> #include <string> #include <string.h> #include <algorithm> using namespace std; int dp[10][10]; void init() { memset(dp,0,sizeof(dp)); dp[0][0] = 1; for(int i=1;i<=10;i++) { for(int j=0;j<10;j++)//枚举第i位可能出现的数 { for(int k=0;k<10;k++)//枚举第i-1位可能出现的数 { if(j!=4&&!(j==3&&k==7)) dp[i][j] += dp[i-1][k]; } } } } int solve(int n) { init(); int digit[10]; int len = 0; while(n>0) { digit[++len] = n%10; n/=10; } digit[len+1]=0; int ans = 0; for(int i=len;i;i--) { for(int j=0;j<digit[i];j++) { if(j!=4&&!(digit[i+1]==3&&j==7)) ans+=dp[i][j]; } if(digit[i]==4||(digit[i]==7&&digit[i+1]==3)) //这里一开始写错,ACdream后台数据貌似小弱,还能AC break; } return ans; } int main() { int l,r; while(cin>>l>>r) { if(l+r==0) break; else cout<<solve(r+1)-solve(l)<<endl; } return 0; }
C - 哗啦啦村的扩建
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 512000/256000KB (Java/Others)Submit Status
Problem Description
呀呀呀,哗啦啦村在日渐发展中,越来越大了。唐老师看到这欣欣向荣的情景,感到非常开心。
狗哥在旁边,“喏,我们村子扩建这么快,肯定用了不少钱吧?”
唐老师说:“是呀,不过这些钱都不及我零花钱的万万分之一。”
那么这时候问题来了,唐老师的零花钱至少应该有多少钱呢?
狗哥也想知道这道题的答案,于是他拜托了青君同学,了解到了村子扩建的费用。
啊,原来村子的扩建费用,就是修建道路的费用。
整个村子可以看作有n个房子,村子会修建n-1条道路,保证从任意房子可以到达任意其他房子。
那修建这n-1条道路的费用怎么记呢?对于每条道路,假设这条道路左边有x个房子,右边有y个房子,这条道路长度为k,那么费用就是k*|x-y|。
那么唐老师的零花钱至少有多少钱呢?现在你应该知道了吧。
Input
第一行一个整数,表示这个村子有n个房子接下来n-1行,表示每条道路的信息,三个整数 a,b,c,表示a,b之间有一条道路,这条路的长度为c
1<=n<=50,000
1≤ai, bi≤n
0 ≤ci≤ 10^6
Output
输出一个整数,表示唐老师的零花钱至少有多少钱
Sample Input
6 1 2 1 1 3 1 1 4 2 6 3 1 5 2 1
Sample Output
2000000000
解题思路:前向星+深搜就可以过,叶节点的累加值初始化为1,深搜更新每个结点的累加值,然后通过前向星枚举每条边得解,注意,输出的时候8个0直接输出,不要再乘,还有注意权值要开long long,统计的结果也要开long long.
AC代码:
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; const int maxn = 1000010; bool vis[maxn]; int head[maxn]; int cnt; int count[maxn]; int m; long long sum; struct Edge { int to; int next; long long w; }edge[maxn]; void add(int u,int v,int w) { edge[cnt].w = w; edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt++; } void dfs(int pos) { int i; vis[pos] = true; for(i=head[pos];i;i=edge[i].next) { if(vis[edge[i].to] == true) continue; //边的邻接点 else { dfs(edge[i].to); count[pos] += count[edge[i].to]; edge[i].w = edge[i].w * abs(m - 2 * count[edge[i].to]); sum += edge[i].w; } } } int main() { int i; int num1,num2,length; //freopen("1.txt","r",stdin); while(cin>>m) { cnt = 1; sum = 0; for(i=1;i<=m;i++) { count[i] = 1; //叶子节点 head[i] = 0; vis[i] = false; } for(i=0;i<m-1;i++) { scanf("%d%d%d",&num1,&num2,&length); add(num1,num2,length); //无向图 add(num2,num1,length); } dfs(1); if(sum != 0) printf("%lld00000000\n",sum); else printf("0\n"); } return 0; }
相关文章推荐
- Matrix理论与应用详解
- 人性漫画:一个人成功前和成功后赤裸裸的区别 人成功前后对比 成功人发展由来前后结果
- 语句和函数
- [iOS]类似新浪微博或者人人客户端中,中间UITabBarItem只有图片,使图片居中的方法
- [FOJ 1890] 竞技游戏
- C++ 编译,运行过程 详解。
- php函数base64_encode后的参数包含加号解析出错的解决方案
- 数据结构-外部排序
- 操作符
- 我所理解的jni与ndk
- 大数的目前水平【大数】
- 1004. 成绩排名
- CF_540C_IceCave
- NYOJ 473 A^B Problem
- LOD设置
- VC的"附加依赖项"、"库目录"和"包含目录"的作用
- java实现随机生成UUID
- 暑假习题 一
- 在spring环境下集成ActiveMQ
- Fragment间进行通信