信息学奥赛一本通 5.1 区间类动态规划

Posted si-rui-yang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了信息学奥赛一本通 5.1 区间类动态规划相关的知识,希望对你有一定的参考价值。

石子合并[loj 10147]

技术分享图片
/* 
dp[i][j]=max or min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]) 
i<=k<j 
*/ 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();}
    return f*ans;
}
int a[401],n,dp_minn[401][401],dp_maxn[401][401],sum[401];
int main()
{
    memset(dp_minn,127,sizeof(dp_minn));
    n=read();
    for(int i=1;i<=n;i++) 
    {
        dp_minn[i][i]=dp_minn[i+n][i+n]=0;
        a[i]=read(),a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i];
    for(int t=2;t<=n;t++)
        for(int i=1;i<=2*n&&i+t-1<=2*n;i++)
        {
            int j=i+t-1;
            
            for(int k=i;k<j;k++)
            {
                dp_maxn[i][j]=max(dp_maxn[i][j],dp_maxn[i][k]+dp_maxn[k+1][j]+sum[j]-sum[i-1]);
                dp_minn[i][j]=min(dp_minn[i][j],dp_minn[i][k]+dp_minn[k+1][j]+sum[j]-sum[i-1]);
            }//cout<<i<<" "<<j<<" "<<dp_minn[i][j]<<endl;
        }
    int maxn=0,minn=2<<30-1;
    for(int i=1;i<=n;i++) maxn=max(maxn,dp_maxn[i][i+n-1]),minn=min(minn,dp_minn[i][i+n-1]);
    cout<<minn<<endl<<maxn; 
}
View Code

能量项链[loj 10148]

技术分享图片
/*
为了好想 记录每一的head和tail
so dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+head[i]*tail[k]*tail[j])  
i<=k<j
*/ 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline long long read()
{
    long long f=1,ans=0;char c;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();}
    return f*ans;
}
long long dp[201][201],a[201],h[201],t[201];
int main()
{
    long long n=read();
    for(long long i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i];
    for(long long i=1;i<2*n;i++) h[i]=a[i],t[i]=a[i+1];
//    for(int i=1;i<2*n;i++) cout<<h[i]<<" "<<t[i]<<endl;
    for(long long tt=1;tt<n;tt++)
        for(long long i=1;i<=2*n&&i+tt<=2*n;i++)
        {
            long long j=i+tt;
//            cout<<i<<" "<<j<<endl;
            for(long long k=i;k<j;k++) dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+h[i]*t[k]*t[j]);
        }
    long long maxn=0;
    for(long long i=1;i<=n;i++) maxn=max(maxn,dp[i][i+n-1]); 
    cout<<maxn;
}
/*
7
23 17 212 113 71 301 33 
31182687
*/
View Code

凸多边形的划分[loj 10149]

技术分享图片
/*
高精度或__int128
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[i]*a[k]*a[j]) 
dp[i][j][0]存位数
其他四个数一个int 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline long long read()
{
    long long f=1,ans=0;char c;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();}
    return ans*f;
}
long long n,a[51]; 
long long dp[110][110][110];
long long s1[110],s2[110],s3[110];
void print()
{
    cout<<dp[1][n][dp[1][n][0]];
    for(long long i=dp[1][n][0]-1;i>=1;i--)
    {
        cout<<dp[1][n][i]/1000;
        cout<<dp[1][n][i]/100%10;
        cout<<dp[1][n][i]/10%10;
        cout<<dp[1][n][i]%10;
    }
}
void mark(long long c[])
{
    for(long long i=1;i<=c[0];i++)
    {
        c[i+1]+=c[i]/10000;
        c[i]%=10000;
    }
    while(c[c[0]+1]!=0)
    {
        c[0]++;
        c[c[0]+1]=c[c[0]]/10000;
        c[c[0]]%=10000;
    }
}
void mul(long long a1,long long a2,long long a3,long long c[])
{
    c[0]=c[1]=1;
    for(long long i=1;i<=c[0];i++) c[i]*=a1;
    mark(c);
    for(long long i=1;i<=c[0];i++) c[i]*=a2;
    mark(c);
    for(long long i=1;i<=c[0];i++) c[i]*=a3;
    mark(c);
}
void add(long long a[],long long b[],long long c[])
{
    if(a[0]>b[0]) c[0]=a[0];
    else c[0]=b[0];
    for(long long i=1;i<=c[0];i++) c[i]=a[i]+b[i];
    mark(c);
}
long long compare(long long a[],long long b[])
{
    if(a[0]>b[0]) return 1;
    if(a[0]<b[0]) return 0;
    for(long long i=a[0];i>=1;i--)
    {
        if(a[i]<b[i]) return 0;
        else if(a[i]>b[i]) return 1;
    }
    return 0;
}
int main()
{
    n=read();
    for(long long i=1;i<=n;i++) a[i]=read();
    for(long long t=2;t<=n-1;t++)
    {
        for(long long i=1;i+t<=n;i++)
        {
            long long j=i+t;
            dp[i][j][0]=60;
            for(long long k=i+1;k<=j-1;k++)
            {
                memset(s1,0,sizeof(s1));
                memset(s2,0,sizeof(s2));
                memset(s3,0,sizeof(s3));
                mul(a[i],a[k],a[j],s1);
                add(dp[i][k],dp[k][j],s2);
                add(s1,s2,s3);
                if(compare(dp[i][j],s3))
                    memcpy(dp[i][j],s3,sizeof(s3));
            }
        }
    }
    print();
}
View Code

括号配对[loj 10150]

技术分享图片
/*
dp[i][j]表示在[i,j]中至少需要添加的数量
1.  (i==[  j==] )  or(i==(   j==))  dp[i][j]=min(dp[i][j],dp[i+1][j-1]
2.  i==( or  i==[ dp[i][j]=min(dp[i][j],dp[i+1][j])
3.  j==) or j==]  dp[i][j]=min(dp[i][j],dp[i][j-1])
4. dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]) (i<=k<j) 


初始化时dp[i][j]=inf  (i<=j) dp[i][i]=1;(1<=i<=n)
想一想为什么 
*/ 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();}
    return f*ans;
}
char str[102];
int a[102];
int dp[110][110],inf=2<<30-1;
int main()
{
//    memset(dp,127,sizeof(dp));
    
    scanf("%s",str+1);
    int len=strlen(str+1);
    for(int i=1;i<=len;i++)
        for(int j=i;j<=len;j++) dp[i][j]=inf;
    for(int i=1;i<=len;i++) 
    {
        dp[i][i]=1;
        if(str[i]==() a[i]=1;
        if(str[i]==)) a[i]=2;
        if(str[i]==[) a[i]=3;
        if(str[i]==]) a[i]=4;
    }
    for(int t=1;t<len;t++)
    {
        for(int i=1;i+t<=len;i++)
        {
            int j=i+t;
            if((a[i]==1&&a[j]==2)||(a[i]==3&&a[j]==4)) dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
            if(a[i]==1||a[i]==3) dp[i][j]=min(dp[i][j],dp[i+1][j]+1);
            if(a[j]==2||a[j]==4) dp[i][j]=min(dp[i][j],dp[i][j-1]+1);
            for(int k=i;k<j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
//            cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
        }
    }
    cout<<dp[1][len];
}
View Code

分离与合体[loj 10151]

技术分享图片
/*
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+(a[i]+a[j])*a[k])
i<=k<j

用last记录
bfs保证了一分为二,二分为四的输出 
*/ 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();}
    return f*ans;
}
int n,a[301],dp[301][301],last[301][301];
void bfs()
{
    queue< pair <int,int > > que;
    que.push(make_pair(1,n));
    while(!que.empty())
    {
        pair<int,int> s=que.front();
        que.pop();
        if(s.first==s.second) continue;
        cout<<last[s.first][s.second]<<" ";
        que.push(make_pair(s.first,last[s.first][s.second]));
        que.push(make_pair(last[s.first][s.second]+1,s.second));
    }
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int t=1;t<n;t++)
        for(int i=1;i+t<=n;i++)
        {
            int j=i+t;
            for(int k=j-1;k>=i;k--) 
            {
                int t=dp[i][k]+dp[k+1][j]+(a[i]+a[j])*a[k];
                if(t>=dp[i][j])
                {
                    dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+(a[i]+a[j])*a[k]);
                    last[i][j]=k;
                }
            }
        }
    cout<<dp[1][n]<<endl;
    bfs();
    return 0;
}
View Code

矩阵取数游戏[loj 10152]

技术分享图片
/*
一行一行处理 
dp[i][j]表示变到 i,j时的最大分数 
dp[i][j]=max(dp[i][j],dp[i-1][j]*a[i-1]^pow(2,n+i-j-1),dp[i][j+1]*a[j+1]^pow(2,n+i-j-1)) 
*/ 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline long long read()
{
    long long f=1,ans=0;char c;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();}
    return f*ans;
}

__int128 dp[101][101],ans,sry[101];
long long n,m,a[101];
void print(__int128 x)
{
    if(x==0) return;
    else if(x!=0) print(x/10);
    putchar(x%10+0);
}
int main()
{
    sry[0]=1;
    for(int i=1;i<=100;i++) sry[i]=sry[i-1]*2;
    n=read(),m=read();
    for(long long i=1;i<=n;i++)
    {
        for(long long j=1;j<=m;j++) a[j]=read();
        memset(dp,0,sizeof(dp));
        for(long long i=1;i<=m;i++)
            for(long long j=m;j>=i;j--) 
                dp[i][j]=max(dp[i-1][j]+a[i-1]*sry[m-j+i-1],dp[i][j+1]+a[j+1]*sry[m-j+i-1]);
        __int128 maxn=-1;
        for(long long i=1;i<=m;i++) maxn=max(maxn,dp[i][i]+a[i]*sry[m]);
        ans+=maxn;
    }
    if(ans==0) 
    {
        cout<<0;return 0;}
    print(ans);
}
View Code

 

以上是关于信息学奥赛一本通 5.1 区间类动态规划的主要内容,如果未能解决你的问题,请参考以下文章

信息学奥赛一本通 5.4 状态压缩动态规划

信息学奥赛一本通要多少钱

信息学奥赛一本通为啥不通过

长春市哪里有卖这本信息学奥赛一本通c++的书店?

信息奥赛一本通 1060:均值

信息学奥赛一本通第三部分_队列 ex2_3produce 产生数