1. 程式人生 > >【洛谷P1982】小朋友的數字

【洛谷P1982】小朋友的數字

就是 提交 負數 else 最大值 const 個數字 狀態 連續

小朋友的數字

沒錯,我又在刷水題

題目鏈接

題目翻譯:

每個小朋友有一個數字,構成一個數字序列a1,a2…an

我們定義“特征值”fi為a1~ai中的最大連續子段和

(不懂請自行百度)

再定義“分數”si為1~i-1中最大的(sj+fj),特殊的,s1=f1,

要求輸出最大的si

DP:

於是我們可以dp求出每個最大連續子段和作為特征值

然後按題意模擬一遍求出每個分數

狀態定義:

dp[i]表示以i為結尾的最大子段和

方程

dp[i]=max(dp[i-1],0)+x; //連著/不連著 前面

f[i]=max(f[i-1],dp[i]);

優化:

空間:

我們發現f[i]、dp[i]都是由f[i-1]、dp[i-1]轉移來的,我們可以考慮將數組降一維 於是空間復雜度就是常數級別的了

時間:

1.1e6的數據快讀是有一定作用的

2.邊讀入邊處理,減少常數

3.由於要用long long,取模運算很慢,可以考慮減少取模次數,當ans>1e17時再取模

#include<cstdio>
using namespace std;
#define int long long
#define N 1000010
#define INF 0x3f3f3f3f
const int ch_top=4e7+3;
char ch[ch_top],*now_r=ch-1,*now_w=ch-1;
inline int read(){  //快讀
    int f=1;
    while
(*++now_r<0) if(*now_r==-) f=-1; register int x=*now_r-0; while(*++now_r>=0)x=(x<<3)+(x<<1)+*now_r-0; return x*f; } inline void write(int x){ //並沒用什麽卵用的快寫 if(x<0){*++now_w=-,x=-x;} static char st[20];static int top; while(st[++top]=0+x%10,x/=10); while
(*++now_w=st[top],--top); *++now_w=\n; } int n,p,dp,ans1,ans; bool flag; #undef int int main() #define int long long { fread(ch,1,ch_top,stdin);//快讀 n=read(); p=read(); int x,f; dp=f=read(); ans1=f;ans=f*2; //特殊處理第一個數 /*ans1為第一個小朋友的分數, ans為其他小朋友的分數的最大值*/ for(int i=2;i<n;i++){ x=read(); dp=(dp>0?dp:0)+x; if(dp>f) f=dp; if(f>0) ans=ans+f; if(ans>1e17) { ans%=p,flag=1; } /*當ans為負時,一定不會是兩個以上的 負數之和,不會爆ll,若取過模,ans一定大於 ans1,用一個flag記錄*/ } if(flag)write(ans%p); else{ if(ans1>ans) ans=ans1; write(ans%p); } fwrite(ch,1,now_w-ch,stdout); //快寫 return 0; }

開O2 32ms ,大概是非打表提交的最優解

【洛谷P1982】小朋友的數字