num1:C++
code:#include<bits/stdc++.h>
using namespace std;
int n,a,b,i,ans=-2147483647;
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a;
if(i==1) b=a;
else b=max(a,a+b);
ans=max(ans,b);
}
cout<<ans;
return 0;
}
解题思路:首先,它读取数列长度及数列元素,并初始化最大和ans为一个极小值。接着,遍历数列,对于每个元素,它考虑两种情况下的累积和:一是仅取当前元素作为新起点,二是当前元素加上之前的累积和。在这两种选择中,它选择较大的值作为新的累积和b。在遍历过程中,不断更新ans为遇到的最大累积和。最终,输出遍历结束后的ans值,即为通过选择性加上前一个数能够得到的最大和。此过程体现了贪心策略与动态规划思想的结合。
num2:C++
code:#include "iostream"
include "stdio.h"
using namespace std;
int w[105],val[105];
int dp[105][1005];
int main()
{
int t,m,res=-1;
scanf("%d%d",&t,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&w[i],&val[i]);
}
for(int i=1;i<=m;i++)
for(int j=t;j>=0;j--)
{
if(j>=w[i])
{
dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j]);
}
else
{
dp[i][j]=dp[i-1][j];
}
}
printf("%d",dp[m][t]);
return 0;
}
解题思路:首先,定义二维数组dp来存储不同物品数量在不同背包容量下的最大价值。然后,读取背包容量t和物品数量m,以及每个物品的重量w和价值val。接下来,使用双重循环遍历物品和背包容量,对于每个物品,判断其是否可放入当前背包容量中。若可放入,则比较放入该物品和不放入该物品时的价值,选择较大者更新dp数组;若不可放入,则保持当前背包容量的最大价值不变。最终,dp[m][t]存储了考虑所有物品且背包容量为t时的最大价值,即为所求。
num3:C++
code:#include <bits/stdc++.h>
define maxn 110
define maxm 100010
using namespace std;
int n,m;
int v[maxn],w[maxn],c[maxn];
int f[maxm],q[maxm];
int calc(int i,int u,int k){
return f[u+kv[i]]-kw[i];
}
int main()
{
memset(f,0xcf,sizeof(f));
scanf("%d%d",&n,&m);
f[0]=0;
for(int i=1;i<=n;i++){
scanf("%d%d%d",&w[i],&v[i],&c[i]);
for(int u=0;u<v[i];u++){
int l=1,r=0;
int maxp=(m-u)/v[i];
for(int k=maxp-1;k>=max(maxp-c[i],0);k--){
while(l<=r&&calc(i,u,q[r])<=calc(i,u,k)) r--;
q[++r]=k;
}
for(int k=maxp;k>=0;k--){
while(l<=r&&q[l]>k-1) l++;
if(l<=r) f[u+kv[i]]=max(f[u+kv[i]],calc(i,u,q[l])+k*w[i]);
if(k-c[i]-1>=0){
while(l<=r&&calc(i,u,q[r])<=calc(i,u,k-c[i]-1)) r--;
q[++r]=k-c[i]-1;
}
}
}
}
int ans=0;
for(int i=1;i<=m;i++)
ans=max(f[i],ans);
printf("%d\n",ans);
return 0;
}
解题思路:首先,初始化背包容量和物品属性,以及动态规划数组f用于存储最大价值。然后,对于每个物品,根据其体积v[i]进行模v[i]的余数u的遍历,以处理不同起始位置的情况。对于每个u,利用单调队列维护一个关于k(表示物品数量)的递减价值序列,其中k的取值范围受背包容量和物品数量限制。通过单调队列快速找到转移最优解,更新f数组。最后,遍历f数组找到最大价值作为答案。此方法有效降低了多重背包问题的时间复杂度。
num4:C++
code:#include
include
include
using namespace std;
const int N=101000;
int b[N],idx[N],n;
int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0' || ch>'9'){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
int main(){
n=read();
memset(b,0x3f,sizeof(b));
for (int i=1;i<=n;i++)
idx[read()]=i;
for (int i=1;i<=n;i++){
int x=idx[read()];
*lower_bound(b+1,b+n+1,x)=x;
}
printf("%d",lower_bound(b+1,b+n+1,b[0])-b-1);
return 0;
}
解题思路:首先将原始数据映射到idx数组中记录其首次出现的位置,以此作为离散化后的索引。接着,再次遍历原始数据,利用idx找到每个值在首次出现时的索引,并使用lower_bound在b数组中找到应插入的位置(保持b数组有序),从而完成离散化过程。由于b数组初始化为极大值,lower_bound实际上是在找第一个未被占用的位置来放置当前索引值。最后,通过lower_bound查找b[0](实际上是一个哨兵值,因为b数组被初始化为极大值)在离散化后的b数组中的位置,减一得到离散化后不同值的数量。
num5:C++
code:#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<vector<int>> dp(n + 1, vector<int>(2, 0));
if (a[1] == 0) {
dp[1][0] = 1;
}
dp[1][1] = 1;
for (int i = 2; i <= n; i++) {
if (a[i] <= i - 1) {
dp[i][0] = dp[i - 1][0] + dp[i - 1][1];
dp[i][0] %= MOD;
}
if (a[i] <= i - 1) {
dp[i][1] = dp[i - 1][0];
dp[i][1] %= MOD;
}
}
int result = (dp[n][0] + dp[n][1]) % MOD;
cout << result << "\n";
}
return 0;
}
解题思路:该代码采用动态规划策略解决问题,定义dp[i][0/1]分别表示考虑到第i个元素时,不选和选该元素的合法方案数。根据a[i]与i-1的大小关系,递推更新dp数组。若a[i]可选(即a[i] <= i-1),则dp[i][0]由dp[i-1][0](不选a[i],继承之前不选的方案)和dp[i-1][1](选a[i-1]但不选a[i])之和得出;dp[i][1]则仅由dp[i-1][0](不选a[i-1],可选a[i])决定。最终,所有合法方案数为dp[n][0] + dp[n][1]。
num6:C++
code:#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a.begin(), a.end());
int aliceCount = 0;
int lastAlice = 0;
int left = 0, right = n - 1;
while (left <= right) {
while (left <= right && a[left] <= lastAlice) {
left++;
}
if (left > right) {
break;
}
aliceCount++;
lastAlice = a[left];
left++;
if (left <= right) {
right--;
}
}
cout << aliceCount << "\n";
}
return 0;
}
解题思路:代码通过贪心策略解决了一个游戏问题,其中Alice和Bob轮流从排序后的石子堆中取石子,Alice先手且每次取的石子必须比上一次大。为了最大化Alice能取的石子次数,Alice会尽量每次都取当前剩余石子中最小的且未取过的石子(满足递增条件)。因此,代码首先对石子进行排序,然后使用双指针(left和right)模拟取石子过程。left指向当前可选的最小石子,right指向最大石子。Alice每次取left指向的石子,并移动left和right指针,直到无法再取。最终输出Alice取石子的次数。

浙公网安备 33010602011771号