HDU1006、3037、2084、1176题解

最近就只有早起做题,做完就上课,周六日可以做些恶心点点的,平时要上课就只有做做DP,数学题什么的了。

HDU1006,十分恶心的一题,实际上我还不是很懂,看着kuangbin大神的代码基本对着拍,没有什么改进。

题目的意思就是时钟里有三条针,时分秒针,两两超过D度就开心,问一天有百分只几是开心的。

思路就是:模拟,区间交,关键,精度问题,这个针算是连续的~不是60秒动一下分针!

/*************************************************************************
> OS     : Linux 3.2.0-60-generic #91-Ubuntu
> Author : yaolong
> Mail   : [email protected]
> Created Time: 2014年05月24日 星期六 07:18:50
************************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
struct segment{
    double l,r;
    segment(){}
    segment(double lt,double rt){
        l=lt;
        r=rt;

    }
    segment(const segment & s){
        l=s.l;
        r=s.r;

    }

};
double D;
segment intersect(segment a,segment b){
    segment p;
    p.l=max(a.l,b.l);
    p.r=min(a.r,b.r);
    if(p.l>=p.r){
        p.l=p.r=0;

    }
    return p;

}
segment  solve(double a,double b){

    //D<=a*x+b<=360-D,求出最大区间[l,r]
    segment p;
    if(a>0){
        p.l=(D-b)/a;
        p.r=(360-D-b)/a;

    }else{
        p.r=(D-b)/a;
        p.l=(360-D-b)/a;

    }
    segment s(0,60);
    return intersect(s,p);

}
double cal(int h,int m){
    double a,b,res=0;
    segment s[3][2];
    segment s1;
    /*
    //double hh=30*h+m/2.0+s/120.0
    //double mm=6*m+s/10
    //double ss=6*s
    //求解D<=|hh-m|<=360-D
    double hh=30*h+m/2.0+1/120.0;
    double mm=6*m+1.0/10;
    double ss=6.0;
    s[0][0]=solve(hh,-mm);
    s[0][1]=solve(-hh,mm);

    //解方程 D<=|hh-ss|<=360-D
    s[1][0]=solve(hh,-ss);
    s[1][1]=solve(-hh,ss);

    //解方程 D<=|ww-ss|<=360-D
    s[2][0]=solve(mm,-ss);
    s[2][1]=solve(-mm,ss);
    */
    //解方程 D<=|hh-mm|<=360-D
    //hh=30*h+m/2+s/120;
    //mm=6*m+s/10;
    a=1.0/120-0.1;
    b=30*h+m/2.0-6*m;
    s[0][0]=solve(a,b);
    s[0][1]=solve(-a,-b);

    //解方程  D<=|hh-ss|<=360-D
    //hh=30*h+m/2+s/120;
    //ss=6*s;
    a=1.0/120-6.0;
    b=30*h+m/2.0;
    s[1][0]=solve(a,b);
    s[1][1]=solve(-a,-b);

    //解方程  D<=|mm-ss|<=360-D
    //mm=6*m+s/10;
    //ss=6*s;
    a=0.1-6;
    b=6*m;
    s[2][0]=solve(a,b);
    s[2][1]=solve(-a,-b);
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            for(int k=0;k<2;k++){

                s1=intersect(intersect(s[0][i],s[1][j]),s[2][k]);
                res+=s1.r-s1.l;

            }

        }

    }
return res;
}
double solve(){
    double res=0;
    for(int i=0;i<12;i++){
        for(int j=0;j<60;j++){
            res+=cal(i,j);
            //        cout<<res<<endl;

        }

    }
    return res*100/(60*60*12);

}
int main(){
    while(scanf("%lf",&D)&&D!=-1){
        printf("%.3lf\n",solve() );

    }
    return 0; 

}

HDU3037

组合数学,裸题一道,Lucas,我还做过一题高校俱乐部的Lucas题目,题目是正多边形对角线,当时看大神们给的公式,完全不理解~对着来拍。

言归正传,这题目意思是n颗树之间最多放m个豆,问有多少种可能。

我们可以这样理解,我们考虑成n+m颗树,之后抽m颗出来,如果我们抽到我们手动添加的树,那么就是有豆没放。这样就是C(n+m,m)%P的结果。

Lucas的用法:p一定要是素数,且数量级在10^5。

我们可以递归成为

C(n,m)%p=C(n%p,m%p)*Lucas(n/p,m/p)

m=0返回1。

另外,这题目交lld会错!!linux用户不服!

/*************************************************************************
    > OS     : Linux 3.2.0-60-generic #91-Ubuntu
    > Author : yaolong
    > Mail   : [email protected]
    > Created Time: 2014年05月24日 星期六 23:30:08
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef  long long LL;
LL fact[100001];
void init(LL p){
    fact[0]=1;
    for(int i=1;i<=p;i++){
        fact[i]=(fact[i-1]*i)%p;
    }
}
LL pow_mod(LL n,LL m,LL p){
    LL res=1;
    while(m){

        if(m&1){
            res=(res*n)%p;
        }
        n=n*n%p;
        m>>=1;
    }
    return res;
}
/*LL Lucas(LL n,LL k,LL p){
    if(k==0)
    return 1;
    LL a=n%p;
    LL b=k%p;
    return fact[a]*pow_mod(fact[b]*fact[a-b],p-2,p)*Lucas(n/p,k/p,p)%p;
}*/
LL Lucas(LL n,LL m,LL p){
    LL ret=1;
    while(n&&m){
        LL a=n%p,b=m%p;
        if(a<b) return 0;
        ret=(ret*fact[a]*pow_mod(fact[b]*fact[a-b]%p,p-2,p))%p;
        n/=p;
        m/=p;
    }
    return ret;
}
int main(){
    int T;
    LL m,n,p,i;

    scanf("%d",&T);
    while(T--){
        scanf("%I64d%I64d%I64d",&m,&n,&p);
        LL res=0;
        init(p);
        res=Lucas(n+m,m,p);
        printf("%I64d\n",res);
    }
   return 0;
}

HDU2084、1176都是经典都不能再经典的数塔dp了,之前对dp基本不做...一直吃亏,现在基础练起。不废话,直接上代码好了。

hdu2084

/***********************************************************
> OS     : Linux 3.2.0-60-generic #91-Ubuntu
> Author : yaolong
> Mail   : [email protected]
> Time   : 2014年05月26日 星期一 07:12:40
**********************************************************/
#include<iostream>
using namespace std;
int dp[105][105];
int main(){
    int T;
    int N;
    cin>>T;
    while(T--){
        cin>>N;
        for(int i=1;i<=N;i++){
            for(int j=1;j<=i;j++){
                cin>>dp[i][j];

            }     

        }
        for(int i=N-1;i>=1;i--)
        {
            for(int j=1;j<=i;j++)
            {
                dp[i][j]=dp[i][j]+max(dp[i+1][j],dp[i+1][j+1]) ;

            }

        }
        cout<<dp[1][1]<<endl;

    }

    return 0;

}

hdu1176

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[100015][12];
int main(){

    int n;
    while(scanf("%d",&n)&&n){

        int t,x;
        int max_t=0;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            scanf("%d%d",&x,&t);
            dp[t][x]++;
            max_t=max(t,max_t);
        }

        for(int i=max_t;i>=0;i--){
            for(int j=0;j<=10;j++){
            if(j>0&&j<10)
            dp[i][j]=dp[i][j]+max(max(dp[i+1][j-1],dp[i+1][j]),dp[i+1][j+1]);
            else if(j==10)
            dp[i][j]=dp[i][j]+max(dp[i+1][j-1],dp[i+1][j]);
            else if(j==0)
            dp[i][j]=dp[i][j]+max(dp[i+1][j+1],dp[i+1][j]);

            }

        }

        printf("%d\n",dp[0][5]);
    }

    return 0;
}

HDU1006、3037、2084、1176题解

时间: 2024-11-11 23:49:34

HDU1006、3037、2084、1176题解的相关文章

完全背包HDU 2159

dp[j][kk]  = max(dp[j][i],dp[j-a[i].cost][kk-1]+dp[a[i].vla]); j个空间里放kk个获得的最大的价值 比一般的完全背包多了一层循环,因为要最多k件 找的时候只要找到第一次>=n的时候就可以了 FATE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 8291    Accept

[HDU1176]免费馅饼(DP)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1176 题解 DP.因为起点固定,终点随意,所以从终点到起点的顺序dp. 代码 import java.util.Scanner; public class FreePie { static final int MAXT=100005; static final int MAXLEN=10; public static void main(String args[]) { Scanner in=new

BZOJ 2084 [Poi2010]Antisymmetry(manacher)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2084 [题目大意] 对于一个01字符串,如果将这个字符串0和1取反后, 再将整个串反过来和原串一样,就称作“反对称”字符串. 比如00001111和010101就是反对称的,1001就不是. 现在给出一个长度为N的01字符串,求它有多少个子串是反对称的. [题解] 修改manacher的判定条件,对该串进行计算即可. [代码] #include <cstdio> #include

3037 插板法+lucas

先说下lucas定理 1)Lucas定理:p为素数,则有: (2)证明: n=(ak...a2,a1,a0)p = (ak...a2,a1)p*p + a0 =  [n/p]*p+a0 (注意 这里()p表示的是p进制数),m=[m/p]*p+b0其次,我们知道,对任意质数p有(1+x)^p=1+(x^p)(mod p) .我们只要证明这个式子:C(n,m)=C([n/p],[m/p]) * C(a0,b0)(mod p),那么就可以用归纳法证明整个定理.对于模p而言,我们有下面的式子成立: 上

POJ 2084 Catalan数

[题意]: 一个环上有2*N个连续的数,求将这些数两两连接且连接的边不相交的方法数. [知识点]: 数学+Catalan数 令h(1)=1,h(0)=1 递归式1:h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2) 递归式2:h(n)=((4*n-2)/(n+1))*h(n-1); 该递推关系的解为:h(n)=C(2n,n)/(n+1) (n=1,2,3,...) [题解]: Catalan数典型的应用,2*N的答案为h(N). [

HDU 1176 免费馅饼:dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1176 题意: 横坐标范围为[0,10],你在第0秒站在坐标为5的地方. 在接下来的一段时间内,会有n个馅饼落下来,每一个馅饼有一个位置x和时刻t. 每一秒你最多可以移动1格.并且在某一个时刻,你只能接到你当前位置的馅饼. 问你最多能接到多少馅饼. 题解: 表示状态: dp[i][j] = max num of pancakes (1)第i秒 (2)站在j的位置 如何转移: 当前dp[i][j]取决于

【醒目】【业界偷懒】【Public】BZOJ题目一句话题解整理

就当是复习一下自己做过的题,顺便提供一个简要题解给大家看. 做题时候实在想不出来看一下一句话题解,可以有一个提示的作用又不至于一下子知道了全部浪费了一道题吧.. 部分题目(如我A过得大部分奶牛题)是别人拿我的账号做的,不提供题解. 可能会漏掉很多做过的题..因为可能点页数不小心点错了什么的 UPD.本来想把那些没写过但是知道题解的也写了..但是写完这些已经累死了QAQ 已AC的题目(数学题均不提供分析过程,公式): 1000:A+B 1001:平面图最小割,转对偶图最短路 1002:矩阵树定理,

HDU 1176(类似数字三角形的题,很经典,值得仔细理解的dp思维)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1176 免费馅饼 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 60927    Accepted Submission(s): 21380 Problem Description 都说天上不会掉馅饼,但有一天gameboy正走在回家的小径

洛谷 P1079 Vigen&#232;re 密码 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1079 题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为 南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用 M 表示:称加密后的信息为密文,用 C 表示:而密钥是一种