P1982小朋友的数字

传送

手疼qwq

 翻译一下题面。就是说,给n个数,第i个数(包括第i个)以及之前的数构成的最大子段和是i的特征值,i以前(不包括i)的数中最大的分数j+特征值j是i的分数,求所有人中的最大分数。

(好吧翻译之后更看不懂了qwq)

 这看起来像一个dp,还是两次dp

  那我们就拿dp试试(太过蒟蒻不会写暴力)

  对于特征值,我也是看了题解才知道这是个最大子段和问题

  那我们看一下最大字段和怎么做

  1.暴力(O(n^3))显然超时,不讨论

  2.分治算法(我不会)

  3.dp(补习完滚回来写博) (O(n)(最快的一种算法))

  所有算法请走这里

  这里我们简单的说一下dp求最大子段和

  设dp[i]是以num[i]结尾的最大子段和(这个子段中一定包含num[i])

  则dp[i]=max(num[i],dp[i-1]+num[i])

  相当于说要么是之前的dp[i-1]再加上num[i]是以num[i]结尾的最大子段和,要么之前的不要了,选a[i]作为dp[i]

  最终答案当然不是dp[n],因为num[n]不一定要在最大子段结尾。

  最终答案是在所有的dp[i]中的最大值

  于是就有了求t[i](特征值)的代码了

 

    long long maxn=-2147483647;
    for(int i=1;i<=n;i++)
    {  
        dp1[i]=max(dp1[i-1]+num[i],num[i]);
        if(dp1[i]>maxn)maxn=dp1[i];
        t[i]=maxn%p;//一个unbelievable的地方:中间不模会炸!!!(就算是小数据也会炸qwq)(未解之谜*1)
        
    } 

 

接下来求分数

未解之谜2警告

我们设maxn为当前所有f[i](分数)中的最大值,那么maxn的转移方程:

maxn=max(maxn,f[i-1]+t[i-1])

f[i]=maxn

未解之谜2:

设f[i]为当前i的分数,则f[i]为之前的所有f[j](1<=j<i)中最大的一个,f[i]=max(f[i-1],f[i-1]+t[i-1])

但上面那个是不对的,这是为什么呢?我也不知道啊。

好了我们自动忽视上面的未解之谜2

如果maxn>ans,则ans=maxn%p(一定要在这里模,放在最后模会wa(未解之谜1))

所以我们就有了ac代码(%%%神仙ych)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1000005;
long long n,p,num[N],dp1[N],f[N],t[N],ans=-2147483647;
int main()
{
    scanf("%lld%lld",&n,&p);
    for(int i=1;i<=n;i++)
     scanf("%lld",&num[i]);
    long long maxn=-2147483647;
    for(int i=1;i<=n;i++)
    {  
        dp1[i]=max(dp1[i-1]+num[i],num[i]);
        if(dp1[i]>maxn)maxn=dp1[i];
        t[i]=maxn%p;
        
    } 
    maxn=-2147483647;
    f[1]=t[1];ans=f[1];
    for(int i=2;i<=n;i++)
    {
        maxn=max(maxn,f[i-1]+t[i-1]);
        f[i]=maxn;
        if(maxn>ans)ans=maxn%p;
        printf("%d %lld\n",i,f[i]);
    }
    cout<<ans;
}

综合两个未接之谜,数据可能有锅

我太菜了,找不到自己的锅

 

ps:如果能回答那两个未解之谜请评论,万谢qwq

 

posted @ 2019-06-19 16:25  千载煜  阅读(191)  评论(0编辑  收藏  举报