zoukankan      html  css  js  c++  java
  • hdu刷题2

    hdu1021

    给n,看费波纳列数能否被3整除

    算是找规律吧,以后碰到这种题就打打表找找规律吧

    #include <stdio.h>  
    int main(void)  
    {  
        int n;  
        while(scanf("%d", &n) != EOF)  
        {  
            if(n%8==2 || n%8==6)  
                printf("yes
    ");  
            else  
                printf("no
    ");  
        }  
        return 0;  
    }
    View Code

    hdu1022 栈的简单利用吧

    给两个队列  看第一个队列是否可以用第二个队列的方式出去

    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    #include<stack>
    using namespace std;
    int main()
    {
        char s1[100],s2[100];
        int n,j,k,f[100];
        stack<char>s;
        while(cin>>n>>s1>>s2)
        {
            while(!s.empty())
            s.pop();
            
            memset(f,-1,sizeof(f));
            j=k=0;
            for(int i=0;i<n;i++)
            {
                s.push(s1[i]);
                f[k++]=1;
                while(!s.empty()&&s.top()==s2[j])
                {
                    f[k++]=0;
                    s.pop();
                    j++;
                }
            }
            if(j==n)
            {
                cout<<"Yes."<<endl;
                for(int i=0;i<k;i++)
                {
                    if(f[i]) cout<<"in"<<endl;
                    else cout<<"out"<<endl;
                }
            }
            else cout<<"No."<<endl;
            printf("FINISH
    ");
        }
        return 0;
    }
    View Code

    hdu1023  什么什么卡特兰数。。。

    这个还是卡特兰数+大数

    https://blog.csdn.net/wu_tongtong/article/details/78161211

    卡特兰数规律

    令h(0)=1,h(1)=1,catalan数满足递推式 [2
    h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n>=2)
    h(n)=C(2n,n)/(n+1) (n=0,1,2,...)
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    int a[110][110];    //大数卡特兰数
    int b[110];         //卡特兰数的长度 
    
    void Catalan(){     //求卡特兰数
        int i,j,len,carry,tmp;
        a[1][0]=b[1]=1;
        len=1;
        for(i=2;i<=100;i++){
            for(j=0;j<len;j++)      //乘法 
                a[i][j]=a[i-1][j]*(4*i-2);
            carry=0;
            for(j=0;j<len;j++){     //处理相乘结果
                tmp=carry+a[i][j];
                a[i][j]=tmp%10;
                carry=tmp/10;
            }
            while(carry){       //进位处理 
                a[i][len++]=carry%10;
                carry/=10;
            }
            //carry=0;
            for(j=len-1;j>=0;j--){  //除法 
                tmp=carry*10+a[i][j];
                a[i][j]=tmp/(i+1);
                carry=tmp%(i+1);
            }   
            while(!a[i][len-1])     //高位零处理
                len--;
            b[i]=len;
        }
    }
    
    int main(){
    
        //freopen("input.txt","r",stdin);
    
        int n;
        Catalan();
        while(~scanf("%d",&n)){
            for(int i=b[n]-1;i>=0;i--)
                printf("%d",a[n][i]);
            printf("
    ");
        }
        return 0;
    }
    View Code

    hdu1024

    又是dp。。。难得一匹,给n个数,你可以划分m个区间,求这些区间的最大值。二维的dp还不行,还要利用滚动数组降维

    https://blog.csdn.net/pmt123456/article/details/52695470 这个解释还是比较好的

    这题给我的启发:dp找方程时,一定要弄清楚会有几个不同的状态,可以事先手动模拟一下。

    比如这题,先是有两个变化的数n和m,那么我就想dp[i][j],有i个区间j个数的最大值。对于ai来数,我就要想到,ai会和哪些dp(上一个)联系起来

    这个数我可以把它当成一个新区间的开始(2) 或者是它不是新区间的开始点(1)

    ①(x1,y1),(x2,y2)...(xi,yi,num[j])

    ②(x1,y1),(x2,y2)...(xi-1,yi-1),...,(num[j]),其中yi-1是第k个数字

    故:d[i][j]=max(  d[i][j-1]   ,  d[i-1][k]   )+num[j],其中k=i-1,i,...,j-1

    优化方法

    注意到,d[i][*]只和d[i][*],d[i-1][*]有关,即当前状态只与前一状态有关,可以用滚动数组完成

    d[t][j]=max(d[t][j-1],d[1-t][k])+num[j],其中k=i-1,i,...,j-1,t=1

    其中只需要记录两个状态,当前状态t=1,上一状态t=0

    空间优化了但时间没有优化

    考虑我们也不需要j-1之前的最大和具体发生在k位置,只需要在j-1处记录最大和即可,用pre[j-1]记录即可

    pre[j-1],不包括num[j-1]的j-1之前的最大和

    则d[t][j]=max(d[t][j-1],pre[j-1])+num[j]

    此时可以看见,t这一维也可以去掉了

    即最终的状态转移为

    d[j]=max(d[j-1],pre[j-1])+num[j]

    #include <iostream>
    #include<cstdio>
    #include<memory.h>
    using namespace std;
    const int maxn=1000005;
    const int maxm=100;
    const int inf=0x7ffffff;
    //int d[maxm][maxn];
    int num[maxn];
    int d[maxn];
    int pre[maxn];
    /*
    int main()
    {
        freopen("in.txt","r",stdin);
        int m,n,tmp;
        while(cin>>m>>n){
            for(int i=1;i<=n;++i){
                cin>>num[i];
            }
            //dp[i][j],第j个人放在第i组时的最大值(1<=i<=j<=n,1<=i<=m)
            for(int i=0;i<=n;++i){
                d[0][i]=0;
                d[i][0]=0;
            }
            for(int i=1;i<=m;++i){
                for(int j=i;j<=n;++j){
                    tmp=-inf;
                    for(int k=i-1;k<=j-1;++k){
                        if(tmp<d[i-1][k])tmp=d[i-1][k];
                    }
                    d[i][j]=max(d[i][j-1],tmp)+num[j];
                }
            }
            cout<<d[m][n]<<endl;
        }
        return 0;
    }
    */
    int main()
    {
        //freopen("in.txt","r",stdin);
        int m,n,tmp;
        while(cin>>m>>n){
            int tmp;
            for(int i=1;i<=n;++i){
                cin>>num[i];
            }
            //dp[i][j],第j个人放在第i组时的最大值(1<=i<=j<=n,1<=i<=m)
            memset(d,0,sizeof(d));
            memset(pre,0,sizeof(pre));
            for(int i=1;i<=m;++i){
                tmp=-inf;
                for(int j=i;j<=n;++j){
                    d[j]=max(d[j-1],pre[j-1])+num[j];
                    pre[j-1]=tmp;
                    tmp=max(tmp,d[j]);
                }
            }
            cout<<tmp<<endl;
        }
     
        return 0;
    }
    View Code

    hdu1025 最长上升子序列+二分优化??????

    https://blog.csdn.net/u011721440/article/details/21107113

    现在,我们仔细考虑计算dp[t]时的情况。假设有两个元素a[x]和a[y],满足 

    (1)x < y < t

    (2)a[x] < a[y] < a[t]

    (3)dp[x] = dp[y]

    此时,选择dp[x]和选择dp[y]都可以得到同样的dp[t]值,那么,在最长上升子序列的这个位置中,应该选择a[x]还是应该选择a[y]呢? 

    很明显,选择a[x]比选择a[y]要好。因为由于条件(2),在a[x+1] ... a[t-1]这一段中,如果存在a[z],a[x] < a[z] < a[y],则与选择a[y]相比,将会得到更长的上升子序列。 

    再根据条件(3),我们会得到一个启示:根据dp[]的值进行分类。对于dp[]的每一个取值k,我们只需要保留满足dp[t] = k的所有a[t]中的最小值。设D[k]记录这个值,即D[k] = min{a[t]} (dp[t] = k)。 

    注意到D[]的两个特点: 

    (1) D[k]的值是在整个计算过程中是单调不上升的。 

    (2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。 

    利用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断a[t]与D[len]。若a [t] > D[len],则将a[t]接在D[len]后将得到一个更长的上升子序列,len = len + 1, D[len] = a [t];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < a[t]。令k = j + 1,则有a [t] <= D[k],将a[t]接在D[j]后将得到一个更长的上升子序列,更新D[k] = a[t]。最后,len即为所要求的最长上 升子序列的长度。 

    在上述算法中,若使用朴素的顺序查找在D[1]..D[len]查找,由于共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的时间复杂度为O(n^2),与原来的算法相比没有任何进步。但是由于D[]的特点(2),我们在D[]中查找时,可以使用二分查找高效地完成,则整个算法的时间复杂度下降为O(nlogn),有了非常显著的提高。需要注意的是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列!

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int a[100005],dp[100005];
    int main()
    {
        int n,x,y,count=1;
        while(~scanf("%d",&n))
        {
            for(int i=1; i<=n; i++)
            {
                scanf("%d%d",&x,&y);
                a[x]=y;
            }
            int len=1;
            dp[1]=a[1];
            for(int i=1; i<=n; i++)
            {
                int l=1;
                int r=len;
                while(l<=r)
                {
                    int mid=(l+r)/2;
                    if(dp[mid]>=a[i])
                        r=mid-1;
                    else
                        l=mid+1;
                }
                dp[l]=a[i];
                if(l>len)
                    len++;
            }
            printf("Case %d:
    My king, at most %d road",count++,len);
            if(len!=1) printf("s");
            printf(" can be built.
    
    ");
        }
    }
    View Code

    hdu1026广搜+优先队列+递归打印路径

    #define _CRT_SECURE_NO_DEPRECATE 
    #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 
     
    #include<iostream>
    #include<algorithm>
    #include<functional>
    #include<vector>
    #include<queue>
     
    using namespace std;
     
    int n, m;
    int dir[4][2] = { { 0,1 },{ 0,-1 },{ 1,0 },{ -1,0 } };
    struct Node
    {
        int time;
        int x, y;
        int prex, prey;
        char ch;
        
        bool operator>(const Node & node) const
        {
            return time > node.time;
        }
     
    }node[105][105];
     
    bool BFS()
    {
        int i;
        int mx, my;
        Node cur;
        priority_queue<Node, vector<Node>, greater<Node> > pq;
     
        node[0][0].time = 0;
        pq.push(node[0][0]);
     
        while (!pq.empty())
        {
            cur = pq.top();
            pq.pop();
            if (cur.x == n - 1 && cur.y == m - 1)
                return true;
            for (i = 0; i < 4; i++)
            {
                mx = cur.x + dir[i][0];
                my = cur.y + dir[i][1];
                if (mx >= 0 && mx < n&&my >= 0 && my < m)
                {
                    if (node[mx][my].ch == '.'&&node[mx][my].time > cur.time + 1)
                    {
                        node[mx][my].time = cur.time + 1;
                        node[mx][my].prex = cur.x;
                        node[mx][my].prey = cur.y;
                        pq.push(node[mx][my]);
                    }
                    else if (node[mx][my].ch >= '1'&&node[mx][my].ch <= '9'&&node[mx][my].time > cur.time + node[mx][my].ch - '0'+1)//注意这里加1
                    {
                        node[mx][my].time = cur.time + node[mx][my].ch - '0' + 1;//注意这里加1
                        node[mx][my].prex = cur.x;
                        node[mx][my].prey = cur.y;
                        pq.push(node[mx][my]);
                    }
                }
            }
        }
     
        return false;
    }
     
    void printPath(int x, int y)
    {
        if (x == 0 && y == 0)
            return;
     
        int prex = node[x][y].prex;
        int prey = node[x][y].prey;
     
        printPath(prex, prey);
     
        int prelength = node[prex][prey].time;
        int length = node[x][y].time;
        printf("%ds:(%d,%d)->(%d,%d)
    ", prelength + 1, prex, prey, x, y);
        for (int i = prelength + 2; i <= length; i++)
        {
            printf("%ds:FIGHT AT (%d,%d)
    ", i, x, y);
        }
    }
     
    int main()
    {
        
        int i, j;
        while (~scanf("%d%d", &n, &m))
        {
            for (i = 0; i < n; i++)
            {
                getchar();
                for (j = 0; j < m; j++)
                {
                    scanf("%c", &node[i][j].ch);
                    node[i][j].time = INT_MAX;
                    node[i][j].x = i;
                    node[i][j].y = j;
                }
            }
     
     
            bool state = BFS();
            if (!state)
            {
                printf("God please help our poor hero.
    ");
                printf("FINISH
    ");
                continue;
            }
            printf("It takes %d seconds to reach the target position, let me show you the way.
    ", node[n - 1][m - 1].time);
            printPath(n - 1, m - 1);
            printf("FINISH
    ");
        }
     
     
        return 0;
    }
    View Code

    hdu1027 n个数字典序排序的第m个排序    全排列也有函数。。。。。。。。。。。

    next_permutation(后一个)和prev_permutation(前一个)函数

    依照STL文档的描写叙述,next_permutation函数将按字母表顺序生成给定序列的下一个较大的序列。直到整个序列为减序为止。prev_permutation函数与之相反。是生成给定序列的上一个较小的序列。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    #define N 1047
    int num[N];
    int main()
    {
        int n , m , i ,k;
        while(~scanf("%d%d",&n,&m))
        {
            memset(num,0,sizeof(num));
            for(i = 0 ; i < n ; i++)
            {
                num[i] = i+1;
            }
            for(i = 1 ; i < m ; i++)
            {
                next_permutation(num,num+n);
            }
            for(i = 0 ; i < n-1 ; i++)
                printf("%d ",num[i]);
            printf("%d
    ",num[n-1]);
        }
        return 0;
    }
    View Code

    hdu1028  母函数和dp  都是大boss。。。

    看了好久模板。。也看得不是太懂,xxde  记住不得了  https://blog.csdn.net/xiaofei_it/article/details/17042651

    /*a[0]=1;
    int last=0;
    
    for(int i=0;i<n;i++)
    {
        int last2=min(last+n[i]*v[i],p);
        memset(b,0,sizeof(int)*(last2+1));
        for(int j=n1[i];j<=n2[i]&&j*v[i]<=last2;j++)
        {
            for(int k=0;k<=last&&k+j*v[i]<=last2;k++)
            b[k+j*v[i]]+=a[k];
        }
        memcpy(a,b,sizeof(int)*(last2+1));
        last=last2;
    }*/
    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    using namespace std;
    int v[122],num[122];
    int a[122],b[122],last,last2;
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1;i<=n;i++)
            v[i]=i,num[i]=n/i;
            //for(int i=1;i<=n;i++)
            //cout<<v[i]<<num[i];
            a[0]=1;
            last=0;
            for(int i=0;i<n;i++)
            {
                int last2=min(last+num[i]*v[i],n);
                memset(b,0,sizeof(int)*(last2+1));
                for(int j=0;j<=num[i]&&j*v[i]<=n;j++)
                {
                    for(int k=0;k<=last&&k+j*v[i]<=last2;k++)
                    b[k+j*v[i]]+=a[k];
                }
                memcpy(a,b,sizeof(int)*(last2+1));
                last=last2;
            }
            cout<<a[n]+1<<endl;
        }
    }
    View Code

    又瞅了瞅dp版的

    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    using namespace std;
    int main()
    {
        int n;
        int dp[121][121];//第一个数表示要组成的数,第二个数为组合数中最大的一个 
        int i,l;
        memset(dp,0,sizeof(dp));
        dp[1][1]=1;
        for(int i=1;i<=120;i++)
        {
            dp[i][1]=1;
            dp[1][i]=1;
        }
        for(int i=2;i<=120;i++)
        {
            for(int j=2;j<=120;j++)
            {
                if(i>j) d[i][j]=d[i-j][j]+d[i][j-1];
                else if(i==j) d[i][j]=1+d[i][j-1];
                else d[i][j]=d[i][i];
            }
        } 
        while(scanf("%d",&n)!=EOF)
        {
            cout<<dp[n][n]<<endl;
        }
        return 0;
    }
    View Code

    想了半天自己对压缩又有点理解了,就是想办法把j或者i通过循环的方式来降维

    比如dp[10][7]=dp[3][7]+dp[10][6]    注意dp[3][7]=dp[3][6];所以最终方程为

    for (int i = 1; i <= 3; i++)
    {
    for (int j = 1; j <= n; j++)
    {
    dp[j] += dp[j - i];
    }
    }

    #include <iostream>
    using namespace std;
    
    const int M = 32768 + 10;
    
    int dp[M];
    
    int main()
    {
        int n;
        while (~scanf("%d", &n))
        {
            memset(dp, 0, sizeof(dp));
            dp[0] = 1;
            for (int i = 1; i <= 3; i++)
            {
                for (int j = 1; j <= n; j++)
                {
                    dp[j] += dp[j - i];
                }
            }
    
            printf("%d
    ", dp[n]);
        }
        return 0;
    }
    View Code

    hdu1029水过

    hdu1030  规律题https://www.cnblogs.com/ACMan/archive/2012/05/30/2526798.html

  • 相关阅读:
    pandas 数据类型研究(三)数据类型object与category
    kaggle比赛实践M5-baseline研读
    pd.melt详解--列转行
    kaggle比赛实践M5-数据集介绍
    kaggle比赛实践M5-比赛介绍
    txNLP 335-374
    信息,熵,联合熵,条件熵,互信息(信息增益),交叉熵,相对熵(KL散度)
    框架SpringMVC笔记系列 二 传值
    项目总结笔记系列 Social Hub KT Session1
    读书笔记系列之java性能优化权威指南 一 第一章
  • 原文地址:https://www.cnblogs.com/wpbing/p/9357682.html
Copyright © 2011-2022 走看看