递推DP

HDU2048 神、上帝以及老天爷

HDU 2006'10 ACM contest的颁奖晚会隆重开始了!
为了活跃气氛,组织者举行了一个别开生面、奖品丰厚的抽奖活动,这个活动的具体要求是这样的:

首先,所有参加晚会的人员都将一张写有自己名字的字条放入抽奖箱中;
然后,待所有字条加入完毕,每人从箱中取一个字条;
最后,如果取得的字条上写的就是自己的名字,那么“恭喜你,中奖了!”

大家可以想象一下当时的气氛之热烈,毕竟中奖者的奖品是大家梦寐以求的Twins签名照呀!不过,正如所有试图设计的喜剧往往以悲剧结尾,这次抽奖活动最后竟然没有一个人中奖!
我的神、上帝以及老天爷呀,怎么会这样呢?
不过,先不要激动,现在问题来了,你能计算一下发生这种情况的概率吗?
不会算?难道你也想以悲剧结尾?!
 Input
输入数据的第一行是一个整数C,表示测试实例的个数,然后是C 行数据,每行包含一个整数n(1<n<=20),表示参加抽奖的人数。Output
对于每个测试实例,请输出发生这种情况的百分比,每个实例的输出占一行, 结果保留两位小数(四舍五入)
Sample Input
1 2
Sample Output
50.00%
 

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
ll D[25];
int main()
{
    D[0]=0,D[1]=0,D[2]=1;
    for(int i=3;i<=20;++i)D[i]=(i-1)*(D[i-1]+D[i-2]);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        double sum=exp(lgamma(n+1));
       // cout<<sum<<' '<<exp(lgamma(n+1))<<endl;//<<' '<<D[n]<<endl;
        printf("%.2lf%%\n",D[n]*100.0/sum);
    }
    return 0;
}

HDU2047 阿牛的EOF牛肉串

今年的ACM暑期集训队一共有18人,分为6支队伍。其中有一个叫做EOF的队伍,由04级的阿牛、XC以及05级的COY组成。在共同的集训生活中,大家建立了深厚的友谊,阿牛准备做点什么来纪念这段激情燃烧的岁月,想了一想,阿牛从家里拿来了一块上等的牛肉干,准备在上面刻下一个长度为n的只由"E" "O" "F"三种字符组成的字符串(可以只有其中一种或两种字符,但绝对不能有其他字符),阿牛同时禁止在串中出现O相邻的情况,他认为,"OO"看起来就像发怒的眼睛,效果不好。
你,NEW ACMer,EOF的崇拜者,能帮阿牛算一下一共有多少种满足要求的不同的字符串吗?
PS: 阿牛还有一个小秘密,就是准备把这个刻有 EOF的牛肉干,作为神秘礼物献给杭电五十周年校庆,可以想象,当校长接过这块牛肉干的时候该有多高兴!这里,请允许我代表杭电的ACMer向阿牛表示感谢!
再次感谢!
Input
输入数据包含多个测试实例,每个测试实例占一行,由一个整数n组成,(0<n<40)。
Output
对于每个测试实例,请输出全部的满足要求的涂法,每个实例的输出占一行。
Sample Input
1
2
Sample Output
3
8

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
ll f[55];
int main()
{
    int n;
    f[1]=3,f[2]=8;//f[3]=22;
    for(int i=3;i<=40;++i)
        f[i]=(f[i-1]+f[i-2])*2;
    while(cin>>n)
    {
        cout<<f[n]<<endl;
    }
    return 0;
}

HDU 2046 

在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数.
例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图:

Input
输入数据由多行组成,每行包含一个整数n,表示该测试实例的长方形方格的规格是2×n (0<n<=50)
Output
对于每个测试实例,请输出铺放方案的总数,每个实例的输出占一行。
Sample Input
1 3 2
Sample Output
1 3 2
不和走楼梯每次走1或者2得一样嘛
 

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
ll f[10005];
int main()
{
    int t,n;
    f[1]=1;f[2]=2;
    for(int i=3;i<=50;++i)
        f[i]=f[i-1]+f[i-2];
    while(cin>>n)
    {
        cout<<f[n]<<endl;
    }
    return 0;
}

HDU 2045 不容易系列之(3)—— LELE的RPG难题
人称“AC女之杀手”的超级偶像LELE最近忽然玩起了深沉,这可急坏了众多“Cole”(LELE的粉丝,即"可乐"),经过多方打探,某资深Cole终于知道了原因,原来,LELE最近研究起了著名的RPG难题:
有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法.
以上就是著名的RPG难题.
如果你是Cole,我想你一定会想尽办法帮助LELE解决这个问题的;如果不是,看在众多漂亮的痛不欲生的Cole女的面子上,你也不会袖手旁观吧?
Input
输入数据包含多个测试实例,每个测试实例占一行,由一个整数N组成,(0<n<=50)。
Output
对于每个测试实例,请输出全部的满足要求的涂法,每个实例的输出占一行。
Sample Input
1
2
Sample Output
3
6
若第n-1个格子和第一个格子不同,则为f(n-1);
若第n-1个格子和第1个格子相同,则第n-2个格子和第一个格子必然不同,此时为f(n-2)再乘第n-1个格子的颜色数,很显然第n-1个格子可以是第一个格子(即第n-2个格子)的颜色外的另外两种,这样为2*f(n-2);
有个坑就是f(3)=3;
 

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
ll f[55];
int main()
{
    int n;
    f[1]=3,f[2]=6;f[3]=6;
    for(int i=4;i<=50;++i)f[i]=f[i-1]+f[i-2]*2;
    while(cin>>n)
    {
        cout<<f[n]<<endl;
    }
    return 0;
}

HDU2044 一只小蜜蜂...
有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
其中,蜂房的结构如下所示。


Input
输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<a<b<50)。
Output
对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。
Sample Input
2 1 2 3 6
Sample Output
1 3
半分钟看题,一分钟半分钟出思路
好,果然wa ,抑郁了,
,,,,没开longlong
 

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
ll f[55];
int main()
{
    int t,a,b;
    f[1]=1,f[2]=1;
    for(int i=3;i<=50;++i)
        f[i]=f[i-1]+f[i-2];
    cin>>t;
    while(t--)
    {
        cin>>a>>b;
        cout<<f[b-a+1]<<endl;
    }
    return 0;
}

HDU 2041  超级楼梯
有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?
Input
输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。
Output
对于每个测试实例,请输出不同走法的数量
Sample Input
2
2
3
Sample Output
1
2

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
ll f[55];
int main()
{
    f[1]=1,f[2]=1;
    for(int i=3;i<=40;++i)
        f[i]=f[i-1]+f[i-2];
    int t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
    cout<<f[n]<<endl;
    }
    return 0;
}

HDU2018 母牛的故事

有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?
Input
输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0<n<55),n的含义如题目中描述。
n=0表示输入数据的结束,不做处理。
Output
对于每个测试实例,输出在第n年的时候母牛的数量。
每个输出占一行。
Sample Input
2 4 5 0
Sample Output
2 4 6
写下前6天得母牛的个数 2 3 4 6 9 13 就会知道f(n)=f(n-1)+f(n-3)

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = (int)1e5 + 10;
typedef long long ll;
int f[60];
int main()
{
    int n;
    f[1]=1,f[2]=2,f[3]=3;
    for(int i=4;i<=55;++i)
        f[i]=f[i-1]+f[i-3];
    while(cin>>n,n!=0)
    {
        cout<<f[n]<<endl;
    }
}


CF687C   The Values You Can Mak
  出题
给你一些硬币,让你选出一个子集的总价值和为k,然后对于一个选出的子集,除了可以组成k以外,还可以在选出的子集中选出一些其他的价值。问你所有的选出的子集一共可以得到多少种价值。 
看的题解:
这个也可以说是一个01背包了,里面也有一些集合的思想在里面,首先dp方程,dp[i][j]代表着当前数值为i,j能否被构成,如果dp[i][j] = 1,那么dp[i+m][j] 和 dp[i+m][j+m] = 1,所以转移方程就写出来了,但是注意我们只能从后向前转移,
也就是说我们一定要用选上一个数的状态,因为这里是01背包,每一个数只能选一次,如果正着选就是完全背包了。
还有就是可以作为母函数的入门题

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
int dp[505][505];
int main()
{
    int n,k,num;
    cin>>n>>k;
    memset(dp,0,sizeof(dp));
    dp[0][0] = 1;
    for(int p=0;p<n;++p)
    {
        cin>>num;
        for(int i = k; i >= num; i--)
        {
            for(int j = 0; j <= k-num; j++)
                if(dp[i-num][j])
                    dp[i][j] = dp[i][j+num] = 1;
        }
    }
    int ans = 0;
    int cnt[555];
    for(int i = 0; i <= k; i++)
    {
        if(dp[k][i])
            cnt[ans++] = i;
    }
    cout<<ans<<endl;
        for(int i=0;i<ans;++i)
         (i==0?(cout<<cnt[i]):(cout<<' '<<cnt[i]));
        cout<<endl;
    return 0;
}

429B 
有一个矩阵,一个人从左上往右下走,一个人从左下往右上走,中间有一次相遇该点的值不算,求最后两人走过路线值之和的最大值(两人重复走过的点只计算一次)

记录矩阵上的每个点分别到矩阵上四个角最大的值,假设某点是相遇点,
该路线的值就是该点到四个角上的最大值之和。因此遍历矩阵上的每个点,求出最大值即可。

首先要保证只有一个格子重合,那么只可能是以下两种情况:
1) A向右走,相遇后继续向右走,而B向上走,相遇后继续向上走
2) A向下走,相遇后继续向下走,而B向右走,相遇后继续向右走
 

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
ll a[1005][1005];
ll dp1[1005][1005];
ll dp2[1005][1005];
ll dp3[1005][1005];
ll dp4[1005][1005];
int main()
{
    int n,m;
    while(cin>>n>>m)
    {

        memset(dp1,0,sizeof(dp1)),memset(dp2,0,sizeof(dp2)),memset(dp3,0,sizeof(dp3)),memset(dp4,0,sizeof(dp4));
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)cin>>a[i][j];
        //   右下
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                dp1[i][j]=max(dp1[i][j-1],dp1[i-1][j])+a[i][j];
        // 右上
        for(int i=n;i>=1;--i)
            for(int j=1;j<=m;++j)
                dp2[i][j]=max(dp2[i][j-1],dp2[i+1][j])+a[i][j];
        //左下
        for(int i=1;i<=n;++i)
            for(int j=m;j>=1;--j)
            dp3[i][j]=max(dp3[i][j+1],dp3[i-1][j])+a[i][j];
        //右上
        for(int i=n;i>=1;--i)
            for(int j=m;j>=1;--j)
                dp4[i][j]=max(dp4[i+1][j],dp4[i][j+1])+a[i][j];

        ll ans=0;
        for(int i=2;i<n;++i)//你总不能然他俩在终点和出发点相遇吧
            for(int j=2;j<m;++j)
                {
                    ans=max(ans,dp1[i-1][j]+dp4[i+1][j]+dp2[i][j-1]+dp3[i][j+1]);
                    ans=max(ans,dp1[i][j-1]+dp4[i][j+1]+dp2[i+1][j]+dp3[i-1][j]);
                }
       cout<<ans<<endl;
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值