题目链接:A - Max Sum Plus Plus
参考博文:Max Sum Plus Plus (动态规划+m子段和的最大值)
代码:
#include
#include
#include
using namespace std;
const int MAX = 1000005;
int dp[MAX], a[MAX];
int Max[MAX];
int main()
{
int n, m;
while(cin >> m >> n)
{
for(int i=1; i<=n; i++)
cin >> a[i];
memset(dp, 0, sizeof(dp));
memset(Max, 0, sizeof(Max));
int mmax;//表示当前最大值
for(int i=1; i<=m; i++)
{
mmax = -1<<29;
for(int j=i; j<=n; j++)
{
dp[j] = max(dp[j-1]+a[j], Max[j-1]+a[j]);
Max[j-1] = mmax;//更新后用于下一个i循环,代表max(dp[i-1][k])
mmax = max(mmax, dp[j]);//一直保持在前
}
}
cout << mmax << endl;
}
return 0;
}
题目链接:B - Ignatius and the Princess IV
代码:
#include
#include
#include
#include
using namespace std;
typedef long long LL;
map<LL, LL> m;
int main()
{
int N;
LL a, ans;
while(scanf("%d", &N)!=EOF)
{
m.clear();
int res = (N+1)/2;
for(int i=0; i<N; i++)
{
scanf("%lld", &a);
m[a]++;
if(m[a]==res) ans = a;
}
printf("%lld\n", ans);
}
return 0;
}
题目链接:C - Monkey and Banana
代码:
#include
#include
#include
#include
#include
using namespace std;
int a[50][5], dp[50][5], n;
void Init(int n)
{
for(int i=0; i<=n; i++)
{
for(int j=0; j<3; j++)
dp[i][j] = 0;
}
}
bool check(int i, int j, int k, int t)
{
vector<int> m1, m2;
for(int h=0; h<3; h++)
{
if(h!=j) m1.push_back(a[i][h]);
if(h!=t) m2.push_back(a[k][h]);
}
if(m1[0]<=m2[0] || m1[1]<=m2[1]) return 0;
else return 1;
}
int DP(int i, int j)
{
int &ans = dp[i][j];
if(ans>0) return ans;
ans = a[i][j];
for(int k=1; k<=n; k++)
{
for(int t = 0; t<3; t++)
{
if(check(i, j, k, t))
{
ans = max(ans, DP(k, t)+a[i][j]);
}
}
}
return ans;
}
int main()
{
int kase = 1;
while(scanf("%d", &n)!=EOF && n)
{
for(int i=1; i<=n; i++)
{
scanf("%d%d%d", &a[i][0], &a[i][1], &a[i][2]);
sort(a[i], a[i]+3);
}
Init(n);
int Max = 0;
for(int i=1; i<=n; i++)
{
for(int j=0; j<3; j++)
{
Max = max(Max, DP(i, j));
}
}
printf("Case %d: maximum height = %d\n", kase++, Max);
}
return 0;
}
题目链接:D - Doing Homework
题目链接:E - Super Jumping! Jumping! Jumping!
代码:
#include
#include
#include
using namespace std;
int main()
{
int N, a[1005], dp[10005];
while(cin >> N && N)
{
for(int i=1; i<=N; i++)
cin >> a[i];
memset(dp, 0, sizeof(dp));
a[0] = -1<<29;
int ans = 0;
for(int i=1; i<=N; i++)
{
for(int j=0; j<i; j++)
{
if(a[j]<a[i])
dp[i] = max(dp[i], dp[j]+a[i]);
}
ans = max(ans, dp[i]);
}
cout << ans << endl;
}
return 0;
}
题目链接:F - Piggy-Bank
代码:
#include
#include
#include
using namespace std;
const int INF = 1<<29;
struct Node
{
int p, w;
};
Node coin[1000];
int dp[10005];//注意数组大小,开小了可能TLE
int main()
{
int T, E, F, N, n;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &E, &F);
N = F-E;
scanf("%d", &n);
fill(dp, dp+N+1, INF);
dp[0] = 0;
for(int i=1; i<=n; i++)
{
scanf("%d%d", &coin[i].p, &coin[i].w);
for(int j=coin[i].w; j<=N; j++)
{
dp[j] = min(dp[j], dp[j-coin[i].w]+coin[i].p);
}
}
if(dp[N]==INF)
printf("This is impossible.\n");
else
printf("The minimum amount of money in the piggy-bank is %d.\n", dp[N]);
}
return 0;
}
题目链接:G - 免费馅饼
参考博文: G. 免费馅饼
代码:
#include
#include
#include
using namespace std;
int a[100005][11], dp[100005][11];//a[i][j]为第i秒的j位置掉下的馅饼数量,dp[i][j]表示第i秒在j位置总共接了多少个馅饼
int dx[5] = {-1, 0, 1};
int DP(int i, int j)
{
int &ans = dp[i][j];
if(ans>0 || i==1) return ans;
int st = 0, ed = 3;
if(j==0) st = 1;
else if(j==10) ed = 2;
for(int k=st; k<ed; k++)
{
ans = max(ans, DP(i-1, j+dx[k])+a[i][j]);
}
return ans;
}
int main()
{
int n, b, c;
while(scanf("%d", &n)!=EOF && n)
{
int T = 0;
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
for(int i=1; i<=n; i++)
{
scanf("%d%d", &b, &c);
a[c][b]++;
if(T<c) T = c;
}
dp[1][4] = a[1][4], dp[1][5] = a[1][5], dp[1][6] = a[1][6];
int Max = 0;
for(int j=0; j<=10; j++)
{
Max = max(Max, DP(T, j));
}
printf("%d\n", Max);
}
return 0;
}
题目链接:H - Tickets
代码:
#include
#include
#include
#include
using namespace std;
const int MAX = 5000;
int a[MAX], b[MAX], dp[MAX];
int DP(int i)
{
if(i<0) return 0;//注意i<0的情况
int &ans = dp[i];
if(ans!=-1) return ans;
if(i>1) ans = min(DP(i-1)+a[i], DP(i-2)+b[i-1]);
else ans = a[i];//i==1时,为a[1]
return ans;
}
int main()
{
int N, K;
scanf("%d", &N);
while(N--)
{
vector<int> ans;
scanf("%d", &K);
for(int i=1; i<=K; i++)
{
scanf("%d", &a[i]);
}
for(int i=1; i<K; i++)
{
scanf("%d", &b[i]);
}
memset(dp, -1, sizeof(dp));
dp[0] = 0;
int t = DP(K);
//换算时间
int h = t/3600+8;
t = t%3600;
int m = t/60;
t = t%60;
printf("%02d:%02d:%02d ", h, m, t);
if(h>=12) printf("pm");//中午12点是pm,晚上12点是am
else printf("am");
printf("\n");
}
return 0;
}
题目链接:I - 最少拦截系统
代码:
#include
#include
#include
#include
#include
using namespace std;
const int MAX = 500000;
int a[MAX], dp[MAX];
vector<int> d;//记录每一个非增子序列的末尾元素,更新时一定是从小到大排好序
int main()
{
int n;
while(scanf("%d", &n)!=EOF)
{
d.clear();
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
fill(dp, dp+n+1, 1);
d.push_back(a[1]);
for(int i=2; i<=n; i++)
{
int j;
for(j=0; j<d.size(); j++)
{
if(d[j]>=a[i])//表明a[i]可以加入d[j]结尾的序列中,因此更新末尾元素
{
d[j] = a[i];
break;
}
}
if(j==d.size()) dp[i] = dp[i-1]+1, d.push_back(a[i]);//表明没有更新
else dp[i] = dp[i-1];
}
printf("%d\n", d.size());
}
return 0;
}
题目链接:J - FatMouse’s Speed
代码:
#include
#include
#include
#include
#include
using namespace std;
struct Node
{
int w, s, id;
bool operator < (const Node &A) const
{
if(w==A.w) return s>A.s;
else return w<A.w;
}
};
Node M[2000];
int pre[10005], dp[2000];//dp表示前i个的子序列长度
int main()
{
int cnt = 1;
while(scanf("%d%d", &M[cnt].w, &M[cnt].s)!=EOF)
{
M[cnt].id = cnt;
cnt++;
}
sort(M+1, M+cnt);
fill(dp, dp+cnt+1, 1);
memset(pre, 0, sizeof(pre));
for(int i=1; i<cnt; i++)
{
for(int j=1; j<i; j++)
{
if(M[j].w<M[i].w && M[j].s>M[i].s)//严格
{
if(dp[i]<dp[j]+1)
{
dp[i] = dp[j]+1;
pre[i] = j;
}
}
}
}
int Max = 0, idx;
for(int i=1; i<cnt; i++)
{
if(Max<dp[i])
{
Max = dp[i];
idx = i;//找出末尾下标
}
}
vector<int> ans;
ans.push_back(M[idx].id);//存储原始编号
while(pre[idx])
{
idx = pre[idx];//反向寻找路径
ans.push_back(M[idx].id);
}
printf("%d\n", Max);
for(int i=ans.size()-1; i>=0; i--)
printf("%d\n", ans[i]);
return 0;
}
题目链接:K - Jury Compromise
题目链接:L - Common Subsequence
代码:
#include
#include
#include
using namespace std;
const int MAX = 1000;
int dp[MAX][MAX];
int main()
{
string s1, s2;
while(cin >> s1 >> s2)
{
int n = s1.size(), m = s2.size();
s1 = " "+s1, s2 = " "+s2;
memset(dp, 0, sizeof(dp));
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(s1[i]==s2[j])
dp[i][j] = dp[i-1][j-1]+1;
else
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
printf("%d\n", dp[n][m]);
}
return 0;
}
题目链接:M - Help Jimmy
参考博文:M - Help Jimmy DP
代码:
#include
#include
#include
#include
using namespace std;
const int INF = 1<<29;
const int MAX = 1005;
struct Node
{
int l, r, h;
}a[MAX];
int dp[MAX][2];
bool cmp(Node a, Node b)
{
return a.h<b.h;
}
void Init(int n)
{
for(int i=0; i<=n+1; i++)
{
for(int j=0; j<2; j++)
dp[i][j] = INF;
}
}
int main()
{
int t, n, x, y, d;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d%d", &n, &x, &y, &d);
Init(n);
for(int i=0; i<n; i++)
{
scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].h);
}
a[n].l = a[n].r = x;
a[n].h = y;
sort(a, a+n, cmp);//按高度从小到大
for(int i=0; i<=n; i++)
{
int lp = -1, rp = -1;//分别为左边和右边板子的编号
for(int j=i-1; j>=0; j--)//从高度比i低的板子中选择左右板子
{
if(lp==-1 && a[j].l<=a[i].l && a[j].r>=a[i].l)
{
lp = j;
}
if(rp==-1 && a[j].r>=a[i].r && a[j].l<=a[i].r)
{
rp = j;
}
}
if(lp==-1)//当不存在左边的板子
{
if(a[i].h<=d) dp[i][0] = 0;//可以直接落到地上
else dp[i][0] = INF;//这边不可以落下
}
if(rp==-1)
{
if(a[i].h<=d) dp[i][1] = 0;
else dp[i][1] = INF;
}
if(lp!=-1 && a[i].h-a[lp].h<=d)//左边的板子可以落下
dp[i][0] = min(dp[lp][0]+a[i].l-a[lp].l, dp[lp][1]+a[lp].r-a[i].l);
if(rp!=-1 && a[i].h-a[rp].h<=d)
dp[i][1] = min(dp[rp][0]+a[i].r-a[rp].l, dp[rp][1]+a[rp].r-a[i].r);
}
printf("%d\n", dp[n][0]+y);
}
return 0;
}
题目链接:N - Longest Ordered Subsequence
代码:
#include
#include
#include
#include
using namespace std;
int a[10005], dp[10005];
int main()
{
int N;
scanf("%d", &N);
fill(dp, dp+N+1, 1);
int ans = 0;
for(int i=1; i<=N; i++)
{
scanf("%d", &a[i]);
for(int j=1; j<i; j++)
{
if(a[j]<a[i])
dp[i] = max(dp[i], dp[j]+1);
}
if(ans<dp[i]) ans = dp[i];
}
printf("%d\n", ans);
return 0;
}
题目链接:O - Treats for the Cows
* 思路:一开始看了样例以为是贪心,但是有反例。实则是区间DP。区间DP一般循环时外层都是区间长度。
* 状态构造:dp[i][j]表示序列的第i个到第j个的最大价值。
* 终态:dp[1][N]。
* 状态转移方程: d p [ i ] [ j ] = m a x ( d p [ i + 1 ] [ j ] + a [ i ] ∗ ( N − ( j − i ) ) , d p [ i ] [ j − 1 ] + a [ j ] ∗ ( N − ( j − i ) ) ) dp[i][j] = max(dp[i+1][j]+a[i]*(N-(j-i)), dp[i][j-1]+a[j]*(N-(j-i))) dp[i][j]=max(dp[i+1][j]+a[i]∗(N−(j−i)),dp[i][j−1]+a[j]∗(N−(j−i))),表示取首部和取尾部的最大值。
* 初始化:dp[i][i] = a[i]*N。
代码:
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAX = 2005;
LL a[MAX], dp[MAX][MAX];
int main()
{
int N;
scanf("%d", &N);
memset(dp, 0, sizeof(dp));
for(int i=1; i<=N; i++)
{
scanf("%d", &a[i]);
dp[i][i] = a[i]*N;
}
for(int len = 2; len<=N; len++)
{
for(int i=1; i<=N; i++)
{
int j=i+len-1;
if(j>N) break;
dp[i][j] = max(dp[i+1][j]+a[i]*(N-(j-i)), dp[i][j-1]+a[j]*(N-(j-i)));
}
}
printf("%lld\n", dp[1][N]);
return 0;
}
题目链接:P - FatMouse and Cheese
代码:
#include
#include
#include
#include
using namespace std;
int n, k;
int G[105][105];
int dp[105][105];
int dx[5] = {0, 0, 1, -1};
int dy[5] = {1, -1, 0, 0};
int DP(int x, int y)
{
int &ans = dp[x][y];
if(ans!=-1) return ans;
ans = G[x][y];
for(int i=1; i<=k; i++)//步数
{
for(int j=0; j<=4; j++)//四个方向
{
int x1 = x+dx[j]*i, y1 = y+dy[j]*i;
if(x1<0 || x1>=n || y1<0 || y1>=n || G[x1][y1]<=G[x][y]) continue;
ans = max(ans, DP(x1, y1)+G[x][y]);//转移方程
}
}
return ans;
}
int main()
{
while(scanf("%d%d", &n, &k)!=EOF && n!=-1)
{
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
scanf("%d", &G[i][j]);
}
}
memset(dp, -1, sizeof(dp));
printf("%d\n", DP(0, 0));
}
return 0;
}
题目链接:Q - Phalanx
参考博文:hdu 2859 (二维dp)
代码:
#include
#include
#include
using namespace std;
int n;
string G[1005];
int dp[1005][1005];//dp[i][j]表示(i, j)为矩阵的左下角
int main()
{
while(cin >> n && n)
{
getchar();
for(int i=0; i<n; i++)
getline(cin, G[i]);
int ans = 0, a, b, len;
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
if(i==0) dp[i][j] = 1;
else
{
a = i, b = j;//a是行,b是列
while(G[a][j]==G[i][b])
{
a--, b++;
if(a<0 || b>=n) break;
}
len = i-a;//对称的长度
if(len>dp[i-1][j+1]) dp[i][j] = dp[i-1][j+1]+1;
else dp[i][j] = len;
}
if(ans<dp[i][j]) ans = dp[i][j];
}
}
printf("%d\n", ans);
}
return 0;
}
题目链接:R - Milking Time
代码:
#include
#include
#include
#include
using namespace std;
const int MAX = 1005;
int N, M, R;
int dp[MAX];
struct Node
{
int st, ed, eff;
bool operator < (const Node &A) const
{
if(ed==A.ed) return st<A.st;
else return ed<A.ed;
}
};
Node T[MAX];
int main()
{
scanf("%d%d%d", &N, &M, &R);
memset(dp, 0, sizeof(dp));
for(int i=1; i<=M; i++)
{
scanf("%d%d%d", &T[i].st, &T[i].ed, &T[i].eff);
}
sort(T+1, T+M+1);
for(int i=1; i<=M; i++)
dp[i] = T[i].eff;
int ans = dp[1];
for(int i=2; i<=M; i++)
{
for(int j=1; j<i; j++)
{
if(T[j].ed+R<=T[i].st)
dp[i] = max(dp[i], dp[j]+T[i].eff);
}
if(ans<dp[i]) ans = dp[i];
}
printf("%d\n", ans);
return 0;
}
题目链接:S - Making the Grade
参考博文:Making the Grade (线性+优化思维?)
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 2005;
const int INF = 1<<30;//29位报错
int n;
int dp[MAXN],a[MAXN],b[MAXN],num[MAXN];
int get_ans(int a[], int num[])
{
memset(dp, 0, sizeof(dp));
for(int i=1; i<=n; i++)
{
int Min = INF;
for(int j=1; j<=n; j++)//得到第i个数变成第j小的数的代价
{
Min = min(Min, dp[j]);//取第i-1个数变成第k(k<=j)小数的最小代价
dp[j] = Min + abs(a[i]-num[j]);
}
}
int ans = INF;
for(int i=1; i<=n; i++) ans = min(ans, dp[i]);
return ans;
}
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++)
{
scanf("%d", &a[i]);
num[i] = a[i];
b[n-i+1] = a[i];//倒序
}
sort(num+1, num+n+1);
printf("%d\n", min(get_ans(a, num), get_ans(b, num)));
return 0;
}