建北電資小社課
有兩個人,場上有n個數字x[i],兩人輪流移除頭或尾的一個數字,移除的數字總和就是得分,假設兩人皆聰明,求第一個人的最大得分。
dp[l][r]表示在l、r區間中第一個人比第二個人多拿的分數
對於l==r的情況,如果是第一個人拿那區間dp[l][r]=x[i]
第二個人 dp[l][r]=-x[i]
第一個人
dp[l][r]=max(dp[l+1][r]+x[l],dp[l][r-1]+x[r])
第二個人
dp[l][r]=min(dp[l+1][r]-x[l],dp[l][r-1]-x[r])
複雜度 \(O(2^n)\)
dp[i][c]表示最小秒數
c(二進)的0表示未打倒
1表示已打倒
i代表單前所在位置
dp[i][0]=i+1;
打倒
tmp=dp[i][c-j];
不整除t[i]: tmp=下一次地屬出現時間
dp[i][c]=min(dp[i][c],tmp)
第二列
第一列
第一行
第二行
第三行
求
dp[n-1]
dp[n-2]
dp[n-1]
dp[n]
const int mod = 1e9 + 7;
struct Mat {
// n*n 方陣
ll A[MAXN][MAXN];
int n;
Mat(int _n){
n=_n;
memset(A, 0, sizeof(A));
}
};
Mat operator *(const Mat &m1, const Mat &m2) {
assert(m1.n == m2.n);
int n = m1.n;
Mat ret(n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
ret.A[i][j] += m1.A[i][k] * m2.A[k][j];
ret.A[i][j] %= mod;
}
}
}
return ret;
}
Mat pow (Mat a, int n) {
Mat ans(a.n);
for (int i = 0; i < a.n; ++i) {
ans.A[i][i]=1;
}
for (int i=1;i<=n;i<<=1) {
if (n&i) ans = ans * a;
a = a * a;
}
return ans;
}
小事伸手