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

原文地址:https://www.cnblogs.com/wpbing/p/9357682.html