当前位置: 首页 > news >正文

2025暑假qbxtNOIP实战梳理营Day1题目

T1

题面

给定一个序列,求将序列分成三段(不能有空),将每一段的和的绝对值加起来的最大值。

题解

前缀和一下,发现分割点为 \(l\) , \(r\) 的情况下贡献为 $ \lvert {sum_{l - 1} } \rvert + \lvert {sum_r - sum_{l - 1} } \rvert + \lvert {sum_n - sum_r} \rvert$ ,分类讨论即可。

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100005
int n,a[N],maxn[N],minn[N];
inline int read(){register int s = 0,w = 1;char ch = getchar();while(!isdigit(ch)){if(ch == '-')w = -1;ch = getchar();}while(isdigit(ch)){s = (s << 3) + (s << 1) + (ch ^ 48);ch = getchar();}return s * w;
}
void Readinit(){n = read();for(int i = 1; i <= n; i++){a[i] = a[i - 1] + read();minn[i] = a[i];maxn[i] = a[i];}
}
void solve(){for(int i = 2; i <= n; i++){minn[i] = min(minn[i - 1],a[i]);maxn[i] = max(maxn[i - 1],a[i]);}int ans = 0;for(int i = 1; i < n; i++){if(a[i] <= a[n] && minn[i - 1] <= a[i] && minn[i - 1] >= 0){ans = max(ans,a[n]);}if(a[i] >= a[n] && a[i] >= minn[i - 1] && minn[i - 1] >= 0){ans = max(ans,2 * a[i] - a[n]);}if(a[i] <= maxn[i - 1] && a[i] <= a[n] && maxn[i - 1] >= 0){ans = max(ans,2 * (maxn[i - 1] - a[i]) + a[n]);}if(a[n] <= a[i] && a[n] <= maxn[i - 1] && maxn[i - 1] >= 0){ans = max(ans,2 * maxn[i - 1] - a[n]);}}for(int i = 1; i < n; i++){if(a[i] <= a[n] && minn[i - 1] <= a[i] && minn[i - 1] < 0){ans = max(ans,a[n] - 2 * minn[i - 1]);}if(a[i] >= a[n] && a[i] >= minn[i - 1] && minn[i - 1] < 0){ans = max(ans,2 * (a[i] - minn[i - 1]) - a[n]);}if(a[i] <= maxn[i - 1] && a[i] <= a[n] && maxn[i - 1] < 0){ans = max(ans,-2 * a[i] + a[n]);}if(a[n] <= a[i] && a[n] <= maxn[i - 1] && maxn[i - 1] < 0){ans = max(ans,a[n]);}}printf("%lld\n", ans);
}
signed main(){int T = 1;while(T--){Readinit();solve();}return 0;
}

T2

题面

给定 \(n\)\(n\) 个整数 \(a_1, a_2, \cdots, a_n\),问至少修改多少个 \(a_i\)(每次修改可以把某个 \(a_i\) 修改成任意值),才能使相邻两个 \(a\) 之间的二进制表示至多有一位不同。

题解

考虑dp,设 \(f_i\) 表示 \(1~i\) 中最多能保留多少,答案明显为 \(n - max\{f_i\}\)

不难想到转移,\(f_i=max^{j=i - 1}_{j = 1} \{[popcount(j - i + 1) \le j - i + 1]f_j\}+1\),复杂度\(O(n^2)\)

考虑优化,不难发现,只有从\(j=i-30\)\(j=i-1\), \(f_j\)的值才有可能最优,仅从前三十转移即可。

代码
#include<bits/stdc++.h>
using namespace std;
#define N 100005
int n,a[N],f[N];
inline int read(){register int s = 0,w = 1;char ch = getchar();while(!isdigit(ch)){if(ch == '-')w = -1;ch = getchar();}while(isdigit(ch)){s = (s << 3) + (s << 1) + (ch ^ 48);ch = getchar();}return s * w;
}
void Readinit(){n = read();for(int i = 1; i <= n; i++){a[i] = read();f[i] = 0;}
}
void solve(){f[1] = 1;for(int i = 2; i <= n; i++){for(int j = max(1,i - 30); j <= i - 1; j++){int x = (a[i] ^ a[j]),k = 0;while(x){++k;x = x - (x & -x);}if(k <= i - j){f[i] = max(f[i],f[j] + 1);}} }int ans = 0;for(int i = 1; i <= n; i++){ans = max(ans,f[i]);}printf("%d\n", max(0,n - ans));
}
signed main(){int T = 1;while(T--){Readinit();solve();}return 0;
}

T3

题面

定义函数 \(f(x)\),若 \(x\) 是偶数,则 \(f(x) = \frac{x}{2}\),否则 \(x\) 是奇数,\(f(x) = 3x + 1\)

给定 \(k\),定义函数 \(g(x)\)\(f(x)\) 调用 \(k\) 次,即 \(g(x) = f(f(\cdots f(x)))\)

\(k = 1\) 时,\(g(x) = f(x)\)\(k = 2\) 时,\(g(x) = f(f(x))\)\(k = 3\) 时,\(g(x) = f(f(f(x)))\),以此类推。

现在给定 \(n, k\),求 \(\sum\limits_{x = 1}^n g(x)\)。由于答案可能很大,只需要输出其对 \(10^9 + 7\) 取模的结果。

题解

一个数列题,考验选手的数学功底。

\(dfs(l,len,d,k)\) 为还剩 \(k\)\(f()\) 操作,数列起点为 \(l\),公差为 \(d\),长度为 \(len\)

分类讨论一下

  • \(d\) 为偶数时,一次操作不会影响奇偶性,往下递归即可。

  • \(d\) 为奇数时,能发现该数列奇偶交错,可以拆成两个等差数列处理。

细节看代码。

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n,k;
int ans = 0;
int dfs(int l,int len,int d,int k){if(k == 0){return (l + l + (len - 1) * d) % mod * (len % mod) % mod * ((mod + 1) / 2) % mod;}if(d % 2 == 0){if(l % 2 == 0){return dfs(l / 2,len,d / 2,k - 1) % mod;}return dfs(l * 3 + 1,len,d * 3,k - 1) % mod;}return (dfs(l,(len + 1) / 2,2 * d,k) + dfs(l + d,len / 2,2 * d,k)) % mod;
}
inline int read(){register int s = 0,w = 1;char ch = getchar();while(!isdigit(ch)){if(ch == '-')w = -1;ch = getchar();}while(isdigit(ch)){s = (s << 3) + (s << 1) + (ch ^ 48);ch = getchar();}return s * w;
}
void Readinit(){n = read();k = read();ans = 0;
}
void solve(){printf("%lld\n", dfs(1,n,1,k));
}
signed main(){int T = 1;while(T--){Readinit();solve();}return 0;
}

T4

题面

给定 \(n, k\)\(a_1, a_2, \cdots, a_n\),现在对于每个 \(1 \le i \le n\)\(i\),求所有满足长为 \(k\) 的序列 \(b_1, b_2, \cdots, b_k\) 满足 \(b_j \ge 1\) 且这个序列所有元素的最小公倍数是 \(i\),其序列元素权值乘积的和。

也就是对每个 \(i\) 求出,所有满足 \(b_1, \cdots, b_k\) 的最小公倍数是 \(i\) 的序列 \(b\)\(a_{b_1} \times a_{b_2} \times \cdots a_{b_k}\) 的和。由于答案可能很大,只需要求出对 \(998244353\) 取模的结果。

题解

设最小公倍数恰好为 \(i\) 的和为 \(f_i\),公倍数为i的和为 \(g_i\)

容易看出 \(g_i = \sum_{j|i} f_j\) ,所以有 \(f_i = g_i - \sum_{j|i且i \neq j} f_j\)

考虑怎么求 \(g_i\) ,会发现这东西特别好求,明显有 \(\g_i=(\sum_{j|i} a_j)^k\)

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100005
const int mod = 998244353;
int n,k,a[N];
int f[N],g[N];
int ksm(int x,int y){int ans = 1;while(y){if(y & 1)ans = ans * x % mod;x = x * x % mod;y >>= 1; }return ans;
}
inline int read(){register int s = 0,w = 1;char ch = getchar();while(!isdigit(ch)){if(ch == '-')w = -1;ch = getchar();}while(isdigit(ch)){s = (s << 3) + (s << 1) + (ch ^ 48);ch = getchar();}return s * w;
}
void Readinit(){n = read();k = read();for(int i = 1; i <= n; i++)a[i] = read();
}
void solve(){for(int i = 1; i <= n; i++){for(int j = 1; i * j <= n; j++){g[i * j] += a[i];g[i * j] %= mod; }}for(int i = 1; i <= n; i++){g[i] = ksm(g[i],k) % mod;f[i] = g[i];}f[1] = ksm(a[1],k) % mod;for(int i = 1; i <= n; i++){for(int j = 2; i * j <= n; j++){f[i * j] -= f[i];f[i * j] = (f[i * j] % mod + mod) % mod;}}for(int i = 1; i <= n; i++)printf("%lld ",f[i]);
}
signed main(){int T = 1;while(T--){Readinit();solve();}return 0;
}

附加

题面

给定 \(n\),求在 \(1 \sim n\) 中选择最多的数,使得选出来的数没有任何两个是整除关系。即不存在 \(i \neq j\)\(i\)\(j\) 的约数且 \(i, j\) 都被选择。

在选出最多数的情况下,还需要最小化选出的数的和。输出这个和。

题解

推一下式子。

代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
inline int read(){register int s = 0,w = 1;char ch = getchar();while(!isdigit(ch)){if(ch == '-')w = -1;ch = getchar();}while(isdigit(ch)){s = (s << 3) + (s << 1) + (ch ^ 48);ch = getchar();}return s * w;
}
void Readinit(){n = read();
}
int ksm(int x,int y){int ans = 1;while(y){if(y & 1)ans *= x;x *= x;y >>= 1;}return ans;
}
void solve(){int ans = 0;if(n % 2 == 0)--n;for(int x = 0; ksm(3,x) <= n; x++){int l = n / ksm(3,x + 1),r = n / ksm(3,x);if(l * ksm(3,x + 1) <= n)++l;if(l % 2 == 0)++l;if(r % 2 == 0)--r;if(l <= r){int d = (r - l) / 2 + 1;ans += ((l + r) * d / 2) * ksm(2,x);}}printf("%lld\n", ans);
}
signed main(){int T = 1;while(T--){Readinit();solve();}return 0;
}
http://www.wuyegushi.com/news/19.html

相关文章:

  • 请求类型绑定响应类型
  • Untitled-1
  • AI代理性能提升实战:LangChain+LangGraph内存管理与上下文优化完整指南
  • GAIA基准测试介绍
  • 多项式全家桶(wjc)
  • 暑假qbxtNOIP实战梳理营Day1题目
  • 7月26日
  • 韦东山:嵌入式Linux全新系列教程之驱动大全(基于IMX6ULL开发板) 视频+资料(60G) 价值1299元
  • ARC200 小记
  • java第二十六天
  • 咕咕嘎嘎!!!(hard)
  • 主流PLC串口自由协议通信标准化
  • 20250726
  • Abp vNext -动态 C# API 实现原理解析
  • 健身营养——Stan Efferding
  • 20250726-31
  • Linux 如何统计系统上各个用户登录(或者登出)记录出现的次数?