ACdream DP专题训练

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
#include
#include 
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>a[i];
        }
        cin>>total;
        Max = a[0];
        for(i=1;i Max)
            {
                Max = a[i]; 
            } 
        }
        //cout<=a[i];j--) //只要大于5就可以再买那个最大的 
                    {
                        if(dp[j] < dp[j-a[i]] + a[i])
                        {
                            dp[j] = dp[j-a[i]] + a[i];
                        }
                    }
                }
            }
        }
        cout<

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和R

1 <= L <= R <= 2000000000 。

Output

输出一个整数,表示选出的数的个数

Sample Input

1 10

Sample Output

9
解题思路:数位DP问题, 数位DP这个链接讲得挺清楚的,ACdream的数据有点小弱,第一次高位和低位写反,竟然还能AC。
AC代码:
#include 
#include 
#include 
#include 
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>l>>r)
    {
        if(l+r==0)
            break;
        else
            cout<


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
#include
#include
#include
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

你可能感兴趣的:(Acdream)