HDU1023——Train Problem II
题目描述
运行代码
#include <iomanip>
#include <iostream>
using namespace std;
void init_a(int a[101][101]);
void printa(int a[101][101], int n);
int main(int ac, char** av) {
int a[101][101] = { 0 };
init_a(a); // 初始化结果
for (int i = 1; i != 101; ++i) {
printa(a, i);
}
return 0;
}
void printa(int a[101][101], int n) {
int j = a[n][0];
if (a[n][j] == 0) {
;
}
else {
cout << a[n][j];
}
--j;
for (; j != 0; --j) {
cout << setw(4) << setfill('0')
<< a[n][j]; // 去除 0356 0056 之类情况 !
}
cout << endl;
}
void init_a(int a[101][101]) {
a[1][1] = 1;
a[2][1] = 2;
a[1][0] = a[2][0] = 1; // a[i][0] 存放数组长度
int i = 0;
for (i = 3; i != 101; ++i) {
int flag = 0;
int temp = 0;
int j = 0;
for (j = 1; j <= a[i - 1][0]; ++j) { // 乘法部分 万位级
// 可能会出现 0000 0354 两类情况 !
temp = a[i - 1][j] * (4 * i - 2) + flag;
a[i][j] = temp % 10000;
flag = temp / 10000;
}
if (flag != 0) { // 检查最高位
a[i][0] = j;
a[i][j] = flag;
}
else {
a[i][0] = j - 1;
}
flag = 0;
for (j = a[i][0]; j != 0; --j) { // 除法部分 万位级
temp = a[i][j] + flag * 10000;
a[i][j] = temp / (i + 1);
flag = temp % (i + 1);
}
j = a[i][0]; // 去除 0000 此类情况 !
if (a[i][j] == 0) {
--a[i][0];
}
}
}
代码思路
-
init_a 函数:这个函数初始化了数列的前100项。它首先设定了前两项为1和2,然后使用嵌套循环来计算剩余的项。每一项的计算涉及到乘法和除法两个阶段:
- 乘法阶段:每一项是前一项乘以一个特定的值,加上一个进位
flag
,然后取模10000得到当前位上的数,进位flag
用于处理超过四位数的情况。 - 除法阶段:每一项再除以后面的一个递增的数(
i + 1
),取整后作为新的项的值,余数作为进位传递给下一位。
- 乘法阶段:每一项是前一项乘以一个特定的值,加上一个进位
-
printa 函数:这个函数负责打印数组中的数列项。它首先检查数组的长度,然后从最高位开始打印每一位,使用
setw
和setfill
来保证输出格式的统一,去除无意义的前导零。 -
main 函数:这是程序的入口点,它初始化数组,然后调用
printa
函数打印出数列的前100项。
HDU1024——Max Sum Plus Plus
题目描述
运行代码
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int m, n;
while (cin >> m >> n) {
vector<int> num(n + 1);
for (int i = 1; i <= n; i++) {
cin >> num[i];
}
vector<int> maxx(n + 1, 0);
for (int i = 1; i <= m; i++) {
int t = 0;
for (int j = 1; j <= i; j++) {
t += num[j];
}
maxx[n] = t;
for (int j = i + 1; j <= n; j++) {
t = max(maxx[j - 1] + num[j], t + num[j]);
maxx[j - 1] = maxx[n];
maxx[n] = max(maxx[n], t);
}
}
cout << maxx[n] << endl;
}
return 0;
}
代码思路
-
读取输入:代码开始时读取两个整数
m
和n
,分别代表数组中可能的起始位置的最大值和数组的长度。 -
初始化数据结构:创建一个
vector<int> num(n + 1)
用于存储输入的整数序列。创建另一个vector<int> maxx(n + 1, 0)
用于存储动态规划过程中的最大值,初始值全部为0。 -
动态规划过程:
外层循环for (int i = 1; i <= m; i++)
遍历所有可能的起始位置。内层循环分为两部分:第二部分for (int j = i + 1; j <= n; j++)
更新maxx
数组,计算以j
结尾的子序列所能达到的最大和。maxx[n] = max(maxx[n], t);
这一行更新了maxx[n]
的值,确保它总是从i
到n
所有可能的子序列中的最大和。maxx[j - 1] = maxx[n];
这一行看起来有些冗余,因为maxx[n]
的值在循环结束后会被覆盖,但在某些实现中可能是为了保持maxx
数组的完整性,或是在之前的代码版本中有其他用途。t = max(maxx[j - 1] + num[j], t + num[j]);
这一行代码意味着在当前位置j
,最大和要么来自于前一个位置j-1
加上当前元素num[j]
,要么来自于从i
到j
的所有元素累积和t
加上当前元素num[j]
。- 第一部分
for (int j = 1; j <= i; j++)
计算从当前位置i
开始的前i
个元素的累积和t
。
-
输出结果:在每次处理完
m
的所有可能起始位置后,输出maxx[n]
,即所有可能子序列中最大的和。
值得注意的是,代码中maxx[j - 1] = maxx[n];
这行代码可能并非必要的,因为maxx[j - 1]
的值在下一次迭代中会被重新计算。但是,保留这行代码不会影响最终结果的正确性,只是可能在某些优化版本中会被去除以提高效率。
HDU1025——Constructing Roads In JGShining's Kingdom
题目描述
运行代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e6+5;
int a[N],dp[N];
int n,t,p,r,k;
int main()
{
int cnt=0;
while(cin>>n){
cnt++;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++){
cin>>p>>r;
a[p]=r;
}
k=1;
dp[k]=a[1];
int l,h,m;
for(int i=2;i<=n;i++){
l=1;
h=k;
while(l<=h){
m=(l+h)>>1;
if(dp[m]<a[i]) l=m+1;
else h=m-1;
}
dp[l]=a[i];
if(l>k) k=l; //表示最长上升子序列个数
}
if(k==1){
printf("Case %d:\nMy king, at most %d road can be built.\n\n",cnt,k);
}else{
printf("Case %d:\nMy king, at most %d roads can be built.\n\n",cnt,k);
}
}
return 0;
}
代码思路
-
输入处理:代码开始读取测试案例的数量,但实际上并没有直接使用一个变量来计数案例,而是通过一个循环和一个外部计数器
cnt
来跟踪案例的数量。对于每一个案例,首先读取项目总数n
,然后读取每个项目的p
和r
,存储在数组a
中。 -
动态规划与二分查找:接下来,代码使用动态规划和二分查找来找到最长递增子序列的长度。
- 初始化
dp
数组,其中dp[k]
将存储长度为k
的最长递增子序列的最后一个元素的最小可能值。 k
变量用于追踪当前已知的最长递增子序列的长度。- 对于每个项目
i
,使用二分查找来确定它可以扩展哪个已存在的递增子序列,或者它自己可以成为一个新的递增子序列的起点。 - 二分查找的核心在于找到第一个大于等于
a[i]
的位置,然后更新该位置的值为a[i]
。如果a[i]
比之前所有的值都要大,那么k
就会增加,表示发现了更长的递增子序列。
- 初始化
-
输出结果:在处理完所有项目后,
k
的值即为最长递增子序列的长度。代码根据k
的值输出相应的结果信息,注意这里根据英语语法,当k
等于1时使用单数形式的名词,大于1时使用复数形式。