C. Mixing Water
题目描述
向一个无穷深的容器轮流倒入温度为 h 的热水和温度为 c 的冷水,至少倒入一次热水,问最接近 t 度时需要倒几杯水。
思路
只要倒入杯数为偶数的情况时,杯中温度都是
h
+
c
2
\frac{h+c}{2}
2h+c,倒入杯数是奇数的情况时,杯中温度都是 (设倒入2n - 1杯)
n
∗
h
+
(
n
−
1
)
∗
c
2
n
−
1
\frac{n*h + (n-1) * c}{2n - 1}
2n−1n∗h+(n−1)∗c 。所以最低温度情况是
h
+
c
2
\frac{h+c}{2}
2h+c,将奇数杯的情况化简不等式:
n
∗
h
+
(
n
−
1
)
∗
c
2
n
−
1
≤
n
∗
h
+
(
n
−
1
)
∗
h
2
n
−
1
\frac{n*h + (n - 1) * c}{2n - 1}\leq\frac{n * h + (n - 1) * h}{2n - 1}
2n−1n∗h+(n−1)∗c≤2n−1n∗h+(n−1)∗h = h
所以最高温是h度,当 t >= h 时特判返回1, t <=
h
+
c
2
\frac{h+c}{2}
2h+c 时特判返回 2 。那么其余的状况就都是奇数的数量。
根据上面的思路分析可得
r
e
s
=
2
∗
n
−
1
res=2*n-1
res=2∗n−1,那么根据公式
n
∗
h
+
(
n
−
1
)
∗
c
2
n
−
1
=
t
\frac{n*h + (n - 1) * c}{2n - 1}=t
2n−1n∗h+(n−1)∗c=t 可以化简得出
n
=
c
−
t
h
+
c
−
2
t
n=\frac{c-t}{h+c-2t}
n=h+c−2tc−t,那么答案
r
e
s
=
2
(
c
−
t
)
h
+
c
−
2
t
−
1
res=\frac{2(c-t)}{h+c-2t}-1
res=h+c−2t2(c−t)−1. 因为这个res求出来是整数,但是可能实际上存在一些精度误差,就要向两边的奇数都去验证一遍寻找最小值
代码
double h, c, t;
double cacl(int x) {
return ((x + 1) / 2 * h + x / 2 * c) / x;
}
void solve() {
cin >> h >> c >> t;
double mid = (h + c) / 2;
if(t <= mid) {
puts("2");
return;
}
if(t >= h) {
puts("1");
return;
}
int l = 1, r = mod;
int res = 2 * (c - t) / (h + c - 2 * t) - 1;
if(!(res & 1)) res ++;
double tmp = cacl(res);
for(int i = max(res - 2, 1); i <= res + 2; i++) {
if(i & 1) {
if(fabs(cacl(i) - t) < tmp) {
tmp = fabs(cacl(i) - t);
res = i;
}
}
}
printf("%d\n", res);
}
D.Yet Another Yet Another Task
题目描述
在给定数组中寻找一个区间 [l, r] ( l ≤ l\leq l≤r) 且减去该区间中最大值的最大值
思路
数据范围 − 30 ≤ a [ i ] ≤ 30 -30\leq a[i] \leq 30 −30≤a[i]≤30,如果是负数的区间最大值那一定只选一个负数并删除它,最大值为0,所以只要枚举最大值为1~30的所有情况。
代码
const int N = 1e5 + 10;
int a[N];
void solve() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
int res = 0;
for(int i = 1; i <= 30; i++) {
int sum = 0;
for(int j = 1; j <= n; j++) {
if(a[j] > i) sum = 0; // 当前存在的数大于所枚举的最大数,当作不存在
else {
sum += a[j];
if(sum < 0) sum = 0;
else res = max(res, sum - i); // sum - i减去区间最大值
}
}
}
printf("%d\n", res);
}
E. Modular Stability
题目描述
给定一个n,k。求有多少组序列{a1, a2, … , ak} 满足 1 ≤ \leq ≤ a1 < a2 < … < ak ≤ \leq ≤ n 且对于任意的数 x 满足按任意顺序取模都相等的结果。
思路
对于任意的数,都要满足 an(n > 1) 为a1的倍数,因为当 an 取模不管取到多少时,满足 x mod an ≥ \geq ≥ x mod a1,若 x mod an > x mod a1, 那么 a1 一定可以再对 x mod an 取模 。这个结论是比较显然的。最后用一下逆元组合数取模的方式就行了
代码
LL f[N], inv[N];
LL kpow(LL a, LL n) {
LL res = 1;
while(n) {
if(n & 1) res = (res * a) % mod;
a = (a * a) % mod;
n >>= 1;
}
return res;
}
void init() {
f[0] = inv[0] = 1;
for(int i = 1; i < N; i++) {
f[i] = (f[i - 1] * i) % mod;
inv[i] = (inv[i - 1] * kpow(i, mod - 2)) % mod;
}
}
void solve() {
init();
int n, k;
scanf("%d%d", &n, &k);
if(n < k) {
puts("0");
return;
}
LL res = 0;
for(int i = 1; i <= n / k; i++) {
LL cnt = n / i;
res = (res + f[cnt - 1] * inv[k - 1] % mod * inv[cnt - k] % mod) % mod;
}
printf("%lld\n", res);
}