DP动态规划(持续更新)

最长不下降子序列

不用我说了吧
有一个O(nlogn)的做法


最长公共子序列

smartoj1212

#include<stdio.h>
using namespace std;
char a[30001],b[30001];
int dp[3001][3001];
int main()
{
    scanf("%s",a+1);scanf("%s",b+1);
    for(int i=1;i<=strlen(a+1);i++)
    for(int j=1;j<=strlen(b+1);j++)
    {
        int pc;
        pc=dp[i-1][j-1]+(a[i]==b[j]);
        dp[i][j]=max(pc,max(dp[i-1][j],dp[i][j-1]));
    }
    printf("%d",dp[strlen(a+1)][strlen(b+1)]);
}

水!


错位排序

有一个东西叫错位排序
hdu2048 有点和排列组合相似

#include<stdio.h>

int main()
{

    int i,n,T;
    double a[21]={0,0,1};
    double b[21]={1,1,2};//定义为double型就不需使用long long,同时输出不需要转换类型
    for(i=3;i<=20;++i)
    {
        a[i]=(a[i-1]+a[i-2])*(i-1); //错排公式--不懂的可以参考信封装错的那题
        b[i]=b[i-1]*i;
    }
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        printf("%.2lf%%\n",a[n]/b[n]*100);
    }
    return 0;
}

不知道自己为什么会错,和正解输出一样qwq


用 1 × 2 的覆盖 2 × n 的矩形

我不会告诉你他是斐波那契数列..

最后一步时,可以竖着放一个1*2的,也可以横着放两个1*2的,这样
f[i]=f[i-1]+f[i-2]


自然数拆分

本题实质为正整数无序分拆,那么设f[i,j]表示数i拆分为j部分的方案数,如果拆分出来的数有1,那么1单独分成一部分,那么有f[i,j-1],无1,那么将已拆分的每一个数减1:f[i-j,j]。

综上有:f[i,j]=f[i,j-1]+f[i-j,j],边界:f[0,0]=0。 结果ans=∑f[n,i](2<=i<=n)

//代码里的i,j好像和题解里反了。。qwq
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
unsigned int n,dp[4005][4005],ans,mod = 2147483648;
int main(){
    cin>>n;
    dp[0][0] = 1;
    for(int i = 1;i <= n;i++){
        for(int j = i;j <= n;j++){
            dp[i][j] = (dp[i-1][j-1] + dp[i][j-i]) % mod;
            if(i > 1 && j == n) ans = (ans + dp[i][j]) % mod;
        }
    }
    cout<<ans;
    return 0;
}

单调栈

有个东西叫单调栈
跟单调队列不同的是单调队列还有长度的限制,单调栈没有 Largest Rectangle in a
Histogram

其实就是一个单调栈,每次把一个矩形最左能到达的地方和最右能到达的地方找出来
最后max ans

#include<iostream>
#include<cstdio>
using namespace std;
long long n,a[100001],b[1000001]/*开始位置*/,c[1000001]/*结束位置*/,
d[1000001],stack[1000001]/*单调栈*/,tail,ans;
int main()
{
//  freopen("1.txt","r",stdin);
    while(scanf("%lld",&n)&&n!=0)
    {
        for(int i=1;i<=n;i++)
        {
            b[i]=c[i]=d[i]=0;
        }
        ans=0;tail=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
        }
        stack[1]=a[1];
        b[1]=1;d[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(a[i]>=stack[tail])
            {
                tail++;
                stack[tail]=a[i];
                d[tail]=i;
                b[i]=i; 
            }
            else
            {
                while(a[i]<stack[tail]&&tail)
                {
                    c[d[tail]]=i-1;
                    tail--;
                }
                b[i]=b[d[++tail]];
                d[tail]=i;
                stack[tail]=a[i];
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(c[i]==0)
            {
                ans=max(ans,a[i]*(n-b[i]+1));
            }
            else ans=max(ans,a[i]*(c[i]-b[i]+1));
        }
        printf("%lld\n",ans);
    }
}

单调队列

Sliding Window
我没有做对,不知道为什么wa。。。
单调队列模板题

#include<iostream>
#include<cstdio>
using namespace std;
int n,a[5000001],head,tail=1,stack[5000001],pos[5000001],k;
int main()
{
//  freopen("1.txt","r",stdin);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    pos[1]=1;
    stack[1]=a[1];
    head=1;
    for(int i=2;i<=n;i++)
    {
        if(pos[head]+k==i) head++;
        if(a[i]>=stack[tail])
        {
            tail++;
            stack[tail]=a[i];
            pos[tail]=i;
        }
        else
        {
            do
            {
                tail--;
            }
            while(a[i]<stack[tail]&&tail>=head);
            stack[++tail]=a[i];
            pos[tail]=i;
            }
            if(i>=k)
            printf("%d ",stack[head]);
    }
    printf("\n");
    for(int i=1;i<=n;i++)
    {
        stack[i]=pos[i]=0;
    }
    head=0;tail=1;
    stack[++head]=a[1];
    pos[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(pos[head]+k==i) head++;
        if(a[i]<=stack[tail])
        {
            stack[++tail]=a[i];
            pos[tail]=i;
        }
        else
        {
            do
            {
                tail--;
            }
            while(a[i]>stack[tail]&&tail>=head);
            stack[++tail]=a[i];
            pos[tail]=i;
        }
        if(i>=k) printf("%d ",stack[head]);
    }
}

我的代码非常好,只是它过不了。。


最大正方形

给你一个01矩阵,求最大的全是1的正方形

//偷别人的代码
#include <stdio.h>  

#define MAX 500  
int matrix[MAX][MAX];  

int min(int a, int b){  
    return a < b ? a : b;  
}  

int main()  
{  
    int max = 1;  
    int m, n;  
    scanf("%d%d", &m,&n);  
    for(int i = 0; i < m; i++)  
        for(int j = 0; j < n; j++)  
            scanf("%d", &matrix[i][j]);  
    for(int i = 1; i < m; i++)  
        for(int j = 1; j < n; j++)  
            if(matrix[i][j] == 1)  
            {  
                int mmin = min(matrix[i - 1][j], matrix[i][j - 1]);  
                mmin = min(matrix[i - 1][j - 1], mmin);  
                matrix[i][j] = mmin + 1;  
                if(max < matrix[i][j])  
                    max = matrix[i][j];  
            }  
    printf("%d", max);  
    return 0;  
}  

设matrix[i][j]表示以(i,j)为右下角的最大正方形边长
初始值1的矩阵matrix值为1
更新时matrix=min(matrix[i - 1][j], matrix[i][j - 1],matrix[i - 1][j - 1])
可以自己画图试一下,很好证明


hdu1003 最大区段和

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int t,a[100001],n,sum,f,l,ff,ll,b;
int main()
{
//  freopen("1.txt","r",stdin);
//  freopen("2.txt","w",stdout);
    cin>>t;
    for(int o=1;o<=t;o++)
    {
        memset(a,0,sizeof(a));
        f=l=1;ff=ll=1;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        sum=a[1];b=a[1];
        for(int i=2;i<=n;i++)
        {
            if(b<0) 
            {
                b=a[i];
                ff=ll=i;
            }
            else
            {
                b=b+a[i];
                ll=i;
            }
            if(b>sum)
            {
                sum=b;
                f=ff;
                l=ll;
            }
        }
        printf("Case %d:\n",o);
        printf("%d %d %d\n",sum,f,l);
        if(o!=t) printf("\n");
    }
} 

poj1050最大子矩阵
和上题一样

//http://poj.org/problem?id=1050
//很水和hdu1003一样 
#include<iostream>
#include<cstdio>
using namespace std;
int n,k,a[101][101],maxn,b;
int main()
{
//  freopen("1.txt","r",stdin);
    cin>>n;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    {
        scanf("%d",&a[i][j]);
        a[i][j]+=a[i-1][j];
    }
    maxn=a[1][1];
    for(int i=1;i<=n;i++)
    for(int j=i;j<=n;j++)
    {
        b=0;
        for(int k=1;k<=n;k++)
        {
            if(b<0) b=a[j][k]-a[i-1][k];
            else b+=a[j][k]-a[i-1][k];
            maxn=max(b,maxn);
        }
    }
    printf("%d",maxn);
}

          \ /
        -->*<--
          /o\
         /_\_\
        /_/_0_\
       /_o_\_\_\
      /_/_/_/_/o\
     /@\_\_\@\_\_\
    /_/_/O/_/_/_/_\
   /_\_\_\_\_\o\_\_\
  /_/0/_/_/_0_/_/@/_\
 /_\_\_\_\_\_\_\_\_\_\
/_/o/_/_/@/_/_/o/_/0/_\
         [___]  

         。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值