dp Lydsy1704月賽 序列操作

2021-08-18 14:36:40 字數 2870 閱讀 6707

4831: [lydsy1704月賽]序列操作

time limit: 1 sec memory limit: 128 mb

submit: 207 solved: 70

[submit][status][discuss]

description

給定乙個長度為 n 的非負整數序列 a_1,a_2,…a_n 。你可以使用一種操作:選擇在序列中連續的兩個正整數,

並使它們分別減一。當你不能繼續操作時遊戲結束,而你的得分等於你使用的操作次數。你的任務是計算可能的最小

得分和最大得分。

input

第一行包含乙個正整數 t ,表示有 t 組資料,滿足 t ≤ 200 。

接下來依次給出每組測試資料。對於每組測試資料:

第一行包含乙個正整數 n ,滿足 1 ≤ n ≤ 10^5 。

第二行包含 n 個非負整數,表示 a_1,a_2,…a_n ,滿足 σa_i ≤ 10^6 。

約 5 組資料滿足 n ≥ 10^3 或 σa_i ≥ 10^4 。

output

對於每組測試資料

輸出一行兩個非負整數,用乙個空格隔開,前者表示可能的最小得分,後者表示可能的最大得分。

sample input

1 2 1 3

1 2 1 1 3

sample output

2 22 3

hint

source

鳴謝tangjz提供試題

顯然是個dp題了。

f[i][j][0/1],表示做到第i個數,他的值為j,前面的數是否存在時的最小運算元

考慮從f[i]轉移到i+1

當j<=a[i+1]的時候,同時減去j

f[i][j][0/1]->f[i+1][a[i+1]-j][0]

當j>a[i+1]的時候,同時減去a[i+1]

f[i][j][0]->f[i+1][0][1]

當i-1為0時,列舉k<=min(j-1,a[i+1])

f[i][j][0]->f[i+1][a[i+1]-k][1]

容易發現當k從大到小列舉的時候,只要算f[i][j][0]的字尾最小值即可。

最大值類似處理即可

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

typedef

double db;

int n,m;

inline

int read()

const

int inf=707406378;

const

int n=1e6+7;

int f[n][2],g[n][2],h[n][2],a[n],max;

inline

void solve()

max=0;

for(int i=1;i<=n;++i) a[i]=read(),max=max(max,a[i]);

// memset(f,127/3,sizeof(f));

for(int i=0;i<=max;++i) f[i][0]=f[i][1]=inf;

f[a[1]][0]=0;

for(int i=1;ifor(int j=0;j<=a[i];++j) h[j][0]=f[j][0],h[j][1]=f[j][1];

for(int j=0;j<=a[i];++j) f[j][0]=f[j][1]=inf;

for(int j=0;j<=a[i];++j)

int tmp=1e9,t=min(a[i]-1,a[i+1]);

for(int j=t+1;j<=a[i];++j) tmp=min(tmp,h[j][0]);

for(int k=min(a[i]-1,a[i+1]);k>=0;--k)

}int tmp=min(f[0][1],f[0][0]);

for(int i=1;i<=a[n];++i)

tmp=min(tmp,f[i][0]);

printf("%d ",tmp);

for(int i=0;i<=max;++i) f[i][0]=f[i][1]=0;

// memset(f,0,sizeof(f));

f[a[1]][0]=1;

for(int i=1;ifor(int j=0;j<=a[i];++j) h[j][0]=f[j][0],h[j][1]=f[j][1];

for(int j=0;j<=a[i];++j) f[j][0]=f[j][1]=0;

for(int j=0;j<=a[i];++j)

if(h[j][0]||h[j][1])

int tmp=0,t=min(a[i]-1,a[i+1]);

for(int j=t+1;j<=a[i];++j) tmp=max(tmp,h[j][0]);

for(int k=min(a[i]-1,a[i+1]);k>=0;--k)

}tmp=0;

if(f[0][1]!=inf) tmp=max(tmp,f[0][1]);

if(f[0][0]!=inf) tmp=max(tmp,f[0][0]);

for(int i=1;i<=a[n];++i)

if(f[i][0]!=inf)

tmp=max(tmp,f[i][0]);

printf("%d\n",tmp-1);

}int main()

牛客小白月賽 小A的回文串

時間限制 c c 2秒,其他語言4秒 空間限制 c c 262144k,其他語言524288k 64bit io format lld 一行乙個字串表示給定的字串s一行乙個字串表示給定的字串s一行輸出乙個整數,表示通過這樣的操作後可以得到最大回文子串的長度。示例1 複製dcbaabc複製 7將前面的...

牛客小白月賽4 F 等價串題解

演算法分析 解題 一串長度為n的字串a和一串長度為m的字串b。並且這兩串字串只會含有0或1。鐵子可以對字串a執行兩種操作,兩種操作可以執行任意次。現在問,字串a可以變成字串b嗎?第一行有乙個整數t,表示有 t 1 t 1000 組測試資料。接下來的每組資料,第一行有兩個整數n,m 1 n,m 100...

洛谷 3月月賽T4 序列 貪心構造 DP

傳送門 luogup5241 一波找規律嘗試出n 4n 4 n4分做法,然而實際上是個貪心構造轉dp 考慮如何構造出一組合法序列 首先讓所有邊首尾相連形成鏈,如果scc數量產生變化,就縮鏈上開頭的一部分。在兼顧scc數量變化的同時,其它邊均貪心地用於串鏈,直到所有點都被串在了鏈上 這時就可以隨便連了...