2020 China Collegiate Programming Contest, Weihai Site L. Clock Master(分组背包/数论)
With the rapid development of society, the demand for high-precision clocks is constantly rising. Recently, the China Clock Production Company is developing a new type of clock, which can represent a wide range of times.
The novel clock displays the current time in an unusual fashion. The clock consists of several pointers, each controlled by a gear. All gears rotate synchronously – one tooth per period. However, the numbers of teeth of the gears may differ. If a gear has 𝑡t teeth, then the corresponding pointer can point to 𝑡t different directions, denoted 0,1,2,⋯,𝑡−10,1,2,⋯,t−1, respectively, where 00 is the initial direction. Furthermore, if a clock is equipped with 𝑛n pointers, the 𝑖i-th of which is controlled by a 𝑡𝑖ti-tooth gear, then the 𝑖i-th pointer will point to 𝑘mod𝑡𝑖kmodti after 𝑘k periods of time.
The price for a 𝑡t-tooth gear is 𝑡t yuan. Given a total budget of 𝑏b yuan, you need to design a combination of gears, such that the number of valid combinations of directions of pointers is maximized, and the total cost on gears does not exceed the budget. A combination of directions (𝑑1,𝑑2,⋯,𝑑𝑛)(d1,d2,⋯,dn) is valid, if it can be written
(𝑘mod𝑡1,𝑘mod𝑡2,⋯,𝑘mod𝑡𝑛)(kmodt1,kmodt2,⋯,kmodtn)
for some nonnegative integer 𝑘k, where 𝑡𝑖ti is the number of teeth of the 𝑖i-th gear. Since the answer may be too large, output the answer in natural logarithm (logarithm with base 𝑒=2.718281828⋯)e=2.718281828⋯).
Input
The first line of input is a single integer 𝑇T (1≤𝑇≤30000)(1≤T≤30000), indicating the number of test cases. Each test case is a single line of an integer 𝑏b (1≤𝑏≤30000)(1≤b≤30000), denoting the total budget.
Output
For each test case, print the natural logarithm, within an absolute or relative error of no more than 10−610−6, of the maximum number of valid combinations, in a single line.
Example
input
Copy
3
2
7
10
output
Copy
0.693147181
2.484906650
3.401197382
题意看了好半天没看明白,其实就是给定一个数b,找到若干个数,使得这若干个数的最小公倍数最大同时保证这些数的和小于等于b。输出对这个最大的最小公倍数取ln的结果。
因为想要让最小公倍数最大,肯定希望这若干个数尽可能两两互质。考虑如何选取。由唯一分解定理可知,一个数总能写成若干个质数的次幂的乘积,两个数互质当且仅当其唯一分解后的公共质因子的幂次为0。同时,假设我们选了两个数,其唯一分解后得到,则,但如果我们选择,其lcm也为,且这样选择更优,因为当a, b不为1时,所以分开后费用更小。所以考虑选择质数的次幂。因为,所以实际上每个素数只选择一个次幂,这就抽象成了一个分组背包的模型。设dp[i, j]表示从前i组素数次幂中选取和为j的数能得到的最大的lcm取ln得到的答案。由于要求输出的是取ln的答案,因此预处理出ln[x]数组后就能很方便地转移了。预处理出dp数组,询问时直接查询输出即可。
#include <bits/stdc++.h>
using namespace std;
double dp[305][30005];//dp[i][j]表示从前i组素数次幂中选取和为j的数能得到的最大的lcm取ln得到的答案
const double E = 2.718281828459;
double ln[30005];
int p[30005], m = 0;
bool vis[30005] = { 0 };
void primes(int n) {
for(int i = 2; i <= n; i++) {
if(vis[i]) continue;
m++;
p[m] = i;
for(int j = 1; i * j <= n; j++) vis[i * j] = 1;
}
}
int main() {
int t;
cin >> t;
primes(30000);
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= 30000; i++) {
ln[i] = log(i) * 1.0 / log(E);
}
for(int i = 1; i <= 303; i++) {
for(int j = 1; j <= 30000; j++) {
int np = p[i];
for(int k = 1; np <= 30000; k++) {//np是p[i]^k
dp[i][j] = max(dp[i][j], dp[i - 1][j]);
if(j >= np) dp[i][j] = max(dp[i][j], dp[i - 1][j - np] + ln[np]);
np *= p[i];
}
}
}
while(t--) {
long long b;
scanf("%lld", &b);
printf("%.9lf\n", dp[300][b]);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2020-05-12 Codeforces Round #639 (Div. 2) C. Hilbert's Hotel(数学)