Educational Codeforces Round 88 (Rated for Div. 2)(C~E)

比赛连接

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} 2n1nh+(n1)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} 2n1nh+(n1)c2n1nh+(n1)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=2n1,那么根据公式 n ∗ h + ( n − 1 ) ∗ c 2 n − 1 = t \frac{n*h + (n - 1) * c}{2n - 1}=t 2n1nh+(n1)c=t 可以化简得出 n = c − t h + c − 2 t n=\frac{c-t}{h+c-2t} n=h+c2tct,那么答案 r e s = 2 ( c − t ) h + c − 2 t − 1 res=\frac{2(c-t)}{h+c-2t}-1 res=h+c2t2(ct)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 lr) 且减去该区间中最大值的最大值

思路

数据范围 − 30 ≤ a [ i ] ≤ 30 -30\leq a[i] \leq 30 30a[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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值