NOIp2003 数字游戏

Posted zcdhj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIp2003 数字游戏相关的知识,希望对你有一定的参考价值。

套路区间DP题

先跟[NOI2001合并石子]一样,复制一下序列,断环成链。

然后设\(dp[i,j,k]\)为将区间\([i,j]\)分成\(k\)个部分相乘的最优解,可以得出如下状态转移方程

\[dp[i,j,k]=\max_{i+k-2≤g<r} \{dp[i,g,k-1]·sum[g+1,j]\}\]

\(sum?\)用前缀和来维护,注意一下\(Mod?\)运算和取余运算不同,如果为负数则需要变成正数。

#include <bits/stdc++.h>

#define Mod(x) (x=((x%mod)+mod)%mod)

const int max_n=50+5;
const int max_m=10+5;
const int mod=10; 
const int inf=0x3f3f3f3f;

int N,M,Ans1=inf,Ans2;
int dp[2][max_m][max_n][max_n],sum[max_n<<1];

inline int read()
{
    register int x=0,v=1;
    register char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch==‘-‘) v=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+ch-‘0‘;
        ch=getchar();
    }
    return x*v; 
}

int main()
{
    int t;
    N=read(),M=read();
    for(int i=1;i<=N;++i)
        sum[i]=sum[i+N]=read();
    for(int i=1;i<=N<<1;++i)
        sum[i]+=sum[i-1];
    for(int i=1;i<=N;++i)
        for(int j=i;j<=i+N-1;++j)
            dp[0][1][i][j]=dp[1][1][i][j]=sum[j]-sum[i-1],Mod(dp[0][1][i][j]),Mod(dp[1][1][i][j]);
    for(int i=2;i<=M;++i)
    {
        for(int l=1;l<=N;++l)
        {
            for(int r=l+i-1;r<=l+N-1;++r)
            {
                dp[0][i][l][r]=inf;
                for(int k=l+i-2;k<r;++k)
                {
                    t=sum[r]-sum[k],Mod(t);
                    dp[0][i][l][r]=std::min(dp[0][i][l][r],dp[0][i-1][l][k]*t);
                    dp[1][i][l][r]=std::max(dp[1][i][l][r],dp[1][i-1][l][k]*t);
                }
            }
        }
    }
    for(int i=1;i<=N;++i)
        Ans1=std::min(Ans1,dp[0][M][i][i+N-1]),Ans2=std::max(Ans2,dp[1][M][i][i+N-1]);
    printf("%d\n%d\n",Ans1,Ans2);
    return 0;
}

以上是关于NOIp2003 数字游戏的主要内容,如果未能解决你的问题,请参考以下文章

NOIp2003 数字游戏

[NOIP2003] 提高组 洛谷P1039 侦探推理

codevs 1085 数字游戏 dp或者暴搜

codevs 1085

noip2003 麦森数

cogs 106. [NOIP2003] 加分二叉树(区间DP)