數字遊戲 解題報告

2021-10-09 20:18:51 字數 1746 閱讀 1123

題目鏈結

題目大意:有一圈整數(一共n個),按順序將其分為m個部分,各部分內的數字相加,相加所得的m個結果對10取模後再相乘,最終得到乙個數k。要求是使你所得的k最大或者最小。

題目分析

1.首先對於環狀的題目首先想到的就是將環狀的轉化為線性的,這也將大大簡化我們解題的過程。我們可以將環從n和1中間斷開,將兩個數段拼到一起,效果就是:

a1,a2,……,an-1,an,a1,a2……,an-1

最後不要an的原因是所有的結果都會在長度為n的區間完成,而最遠的點就是an->an-1,所以不需要an。

2.而面對要分成m個部分的這種題,前x-1個部分的情況不影響第x組的結果,所以很容易想到用動態規劃的方法來儲存前i個元素分成j部分的最大最小值。因為我們把環變成了乙個數段,所以可以直接列舉起點和終點。

3.狀態轉移方程如下:

dp[l][r][j][0]=min(dp[l][r][j][0],dp[l][k][j-1][0] * (pre[r]-pre[k]));

dp[l][r][j][1]=max(dp[l][r][j][1],dp[l][k][j-1][1] * (pre[r]-pre[k]));

l:起點,r:終點,j:分成的部份數。0,1:最大值還是最小值。

pre陣列記錄的是字首和(這是乙個很容易想到的優化)

正解程式

#include

#include

#include

#include

#include

#include

#define inf 0x7ffffff

using

namespace std;

typedef

long

long ll;

const ll maxn=

100;

ll n,m,a[maxn]

,pre[maxn]

;ll dp[maxn]

[maxn][20

][2]

;void

init()

}}}int

main()

for(ll i=n+

1;i<=

2*n;i++

) pre[i]=(

(pre[i-1]

+a[i-n])%

10+10)

%10;for

(ll l=

1;l<=n;l++

)for

(ll r=l;r<=

min(l+n-1,

2*n-1)

;r++

) dp[l]

[r][1]

[0]=dp[l]

[r][1]

[1]=

((pre[r]

-pre[l-1]

)%10+

10)%10

;for

(ll l=

1;l<=n;l++)}

}}ll ans1=inf,ans2=

-inf;

for(ll i=

1;i<=n;i++

)printf

("%lld\n%lld\n"

,ans1,ans2)

;return0;

}

轉圈遊戲 解題報告

轉圈遊戲 noip2013提高組day1 time limit 1000ms memory limit 128000k description 問題描述 circle.cpp c pas n 個小夥伴 編號從 0 到 n 1 圍坐一圈玩遊戲。按照順時針方向給 n 個位置編號,從0 到 n 1。最初,...

A 取石子遊戲(解題報告)

a 取石子遊戲 time limit 1000msmemory limit 10000kb64bit io format i64d i64u submit status description 有兩堆石子,數量任意,可以不同。遊戲開始由兩個人輪流取石子。遊戲規定,每次有兩種不同的取法,一是可以在任意...

取石子遊戲解題報告

有兩堆石子,數量任意,可以不同。遊戲開始由兩個人輪流取石子。遊戲規定,每次有兩種不同的取法,一是可以在任意的一堆中取走任意多的石子 二是可以在兩堆中同時取走相同數量的石子。最後把石子全部取完者為勝者。現在給出初始的兩堆石子的數目,如果輪到你先取,假設雙方都採取最好的策略,問最後你是勝者還是敗者。in...