原題 noip2007 T3 矩陣取數

2022-07-21 00:15:15 字數 3321 閱讀 4322

問題

背景 background

noip2023年提高組第三道

描述 description

帥帥經常跟同學玩乙個矩陣取數遊戲:對於乙個給定的n*m的矩陣,矩陣中的每個元素a[i,j]均為非負整數。遊戲規則如下:

1. 每次取數時須從每行各取走乙個元素,共n個。m次後取完矩陣所有元素;

2. 每次取走的各個元素只能是該元素所在行的行首或行尾;

3. 每次取數都有乙個得分值,為每行取數的得分之和,每行取數的得分 = 被取走的元素值*2^i,其中i表示第i次取數(從1開始編號);

4. 遊戲結束總得分為m次取數得分之和。

帥帥想請你幫忙寫乙個程式,對於任意矩陣,可以求出取數後的最大得分。

輸入格式 input format

輸入檔案game.in包括n+1行:

第1行為兩個用空格隔開的整數n和m。

第2~n+1行為n*m矩陣,其中每行有m個用單個空格隔開的非負整數。

輸出格式 output format

輸出檔案game.out僅包含1行,為乙個整數,即輸入矩陣取數後的最大得分。

分析顯然是一道動規題,怎麼辦捏?仔細想一下,我們發現,這個矩陣的n行互不影響,m次取數對於每行的最優值都是沒有影響的,所以我們可以考慮將矩陣變成數列,逐次對美一行進行動規,那麼顯然,最後的答案就是每行的最優值之和。

一旦我們有了如上的思路,事情就變得很簡單了。方程f[i,j]表示去了i次,從左邊取走了j個。我們可以得到一下的轉移方程f[i,j]:=max要對次方陣列進行預處理。然後求解

由於題目的資料範圍,所以要用壓四位的高精度。

反思自己的方程一開始存在問題,尤其是第二種情況時a陣列的下標沒有找對。以後要細心,仔細推。

這個題看似很難,其實可以轉化為很簡單的問題,關鍵是能看出問題的本質,找出方程。不要被慣性思維限制,敢於想,敢於轉化問題。

code

program liukee;

type

arr=array[0..100] of longint;

var f:array[-1..81,-1..81] of arr;

a:array[1..80] of longint;

cifang:array[0..80] of arr;

ans,tt:arr;

n,m,i,j,r,k,zu:longint;

function max(a,b:arr):arr;

var z:integer;

begin

if a[0]>b[0] then

begin

max:=a;

exit;

end;

if b[0]>a[0] then

begin

max:=b;

exit;

end;

for z:=a[0] downto 1 do

begin

if a[z]>b[z] then

begin

max:=a;

exit;

end;

if b[z]>a[z] then

begin

max:=b;

exit;

end;

end;

max:=a;

end;

operator *(a:arr;x:longint)c:arr;

var i:longint;

begin

fillchar(c,sizeof(c),0);

c[0]:=a[0];

for i:=1 to c[0] do

c[i]:=a[i]*x;

for i:=1 to c[0] do

begin

inc(c[i+1],c[i] div 10000);

c[i]:=c[i] mod 10000;

end;

while(c[c[0]+1]>0)do inc(c[0]);

end;

operator +(a,b:arr)c:arr;

var i:longint;

begin

fillchar(c,sizeof(c),0);

if a[0]>b[0] then c[0]:=a[0]

else c[0]:=b[0];

for i:=1 to c[0] do inc(c[i],a[i]+b[i]);

for i:=1 to c[0] do

begin

inc(c[i+1],c[i] div 10000);

c[i]:=c[i] mod 10000;

end;

while(c[c[0]+1]>0) do inc(c[0]);

end;

procedure outit(a:arr);

var i:longint;

begin

write(a[a[0]]);

for i:=a[0]-1 downto 1 do

begin

write(a[i] div 1000);

write(a[i] div 100 mod 10);

write(a[i] div 10 mod 10);

write(a[i] mod 10)

end;

writeln;

end;

begin

assign(input,'in.txt');reset(input);

readln(n,m);

cifang[0][0]:=1; cifang[0][1]:=1;

for i:=1 to m do cifang[i]:=cifang[i-1]*2;

fillchar(ans,sizeof(ans),0);

for zu:=1 to n do

begin

fillchar(f,sizeof(f),0);

for i:=1 to m do read(a[i]);

for i:=1 to m do

for j:=0 to m do

begin

f[i,j]:=max(f[i,j],f[i-1,j-1]+cifang[i]*a[j]);

f[i,j]:=max(f[i,j],f[i-1,j]+cifang[i]*a[m-i+j+1]);

end;

fillchar(tt,sizeof(tt),0);

for i:=1 to m do tt:=max(tt,f[m,i]);

ans:=ans+tt;

end;

outit(ans);

end.

NOIP2007 矩陣取數遊戲

傳送門給定乙個n m的矩陣,在每一行中取m次數,每次取數只能從行首或尾取數,第i次取數的貢獻是 2 i 該點值 操作n行,求最大答案 n,m 80 不難發現行與行之間是完全獨立的,所以單獨處理每一行就好了 考慮區間dp 設 dp i j 表示區間i j的答案最大值 則有 dp i j max num...

NOIP2007 矩陣取數遊戲

鏈結 簡單dp 毒瘤高精 顯然行與行沒有關聯 所以只需要每行處理 考慮dp i,j,k 表示第i次取數,第j行,有k次取的頭的最大分數 直接dp即可 includeusing namespace std define ll int128inline intread while ch 0 ch 9 d...

noip2007矩陣取數遊戲 2008 11 5

noip2007矩陣取數遊戲 2008.11.5 注意 比大小位數不相同時,取位數大的數大 當位數相同時,要從最高位開始比較,相同,則往下比,不相同,則大的數就大。我剛開始,弄成了從最低位開始比較,故,wa了 20多分鐘 小結 這道題,我打了不下 5遍,一定要先想好,在紙上把每個細節都確定了,並確定...