Codeforces Round #538 (Div. 2)题解报告

Codeforces Round #538 (Div. 2)题解报告

Problem A:Got Any Grapes?

题意

三个瓜皮吃三种葡萄,分别只能吃一种,两种,三种,问能不能都吃够数。

题解

按题意贪心即可。

代码
#include<bits/stdc++.h>
#define Error return puts("NO"), 0
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int x, y, z, a, b, c;
int main() {
	a = ri(); b = ri(); c = ri();
	x = ri(); y = ri(); z = ri();
	x -= a; if(x < 0) Error;
	y += x; y -= b; if(y < 0) Error;
	z += y; z -= c; if(z < 0) Error;
	puts("YES");
	return 0;
}

Problem B:Yet Another Array Partitioning Task

题意

给一个数列让你划分成 k k k段,使得每段前 m m m大之和最大,并输出方案。

题解

直接选前 m ∗ k m*k mk大的数作为答案,凑够了 m m m个数就划分一段即可。

代码
#include<bits/stdc++.h>
const int N = 2e5 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int a[N], id[N], p[N], n, m, k, tp;
bool ok[N];
bool cmp(int x, int y) {return a[x] > a[y];}
int main() {
	n = ri(); m = ri(); k = ri(); long long sum = 0;
	for(int i = 1;i <= n; ++i)
		a[i] = ri(), id[i] = i;
	std::sort(id + 1, id + n + 1, cmp);
	for(int i = 1;i <= m * k; ++i)
		ok[id[i]] = true, sum += a[id[i]];
	int cnt = m;
	for(int i = 1;i <= n; ++i) {
		cnt -= ok[i];
		if(!cnt) p[++tp] = i, cnt = m;
	}
	printf("%lld\n", sum);
	for(int i = 1;i < tp; ++i)
		printf("%d ", p[i]); puts("");
	return 0;
}


Problem C:Trailing Loves (or L’oeufs?)

题意

问十进制的 n ! n! n! B B B进制下尾巴有多少个 0 0 0

题解

实际上就是 B x ∣ ∣ n ! B^x|| n! Bxn!,求 x x x
B = p 1 a 1 p 2 a 2 ⋯ p n a n B=p_1^{a_1}p_2^{a_2}\cdots p_n^{a_n} B=p1a1p2a2pnan
考虑求 p i x i ∣ ∣ n ! p_i^{x_i}||n! pixin!,那么 x = min ⁡ { x i a i } x=\min \{\frac{x_i}{a_i}\} x=min{aixi}
而对于每个 p i p_i pi x i = ∑ k ⌊ n x k ⌋ x_i=\sum_k\lfloor\frac{n}{x^k} \rfloor xi=kxkn(考虑 1 ⋯ n 1\cdots n 1n以内有多少个数整除 x , x 2 ⋯ x k x,x^2\cdots x^k x,x2xk即可)
x i x_i xi本质上是 n n n p i p_i pi进制下的数位和。

代码
#include<bits/stdc++.h>
const int N = 2e6 + 10;
long long ri() {
	char c = getchar(); long long x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
long long ans, n, b, pr[N];
int tp, a[N];
long long Calc(long long n, long long p) {
	long long ans = 0;
	for(n /= p;n; n /= p)
		ans += n;
	return ans;
}
int main() {
	n = ri(); b = ri(); int m = sqrt(b);
	for(int i = 2;i <= m && b != 1; ++i)
		if(!(b % i)) {
			pr[++tp] = i;
			for(;!(b % i); b /= i) ++a[tp];
		}
	if(b > 1) pr[++tp] = b, a[tp] = 1;
	long long ans = 1e18;
	for(int i = 1;i <= tp; ++i)
		ans = std::min(ans, Calc(n, pr[i]) / a[i]);
	printf("%lld\n", ans);
	return 0;
}

Problem D:Flood Fill

题意

给你一个序列,每个位置上有一种颜色,每次你可以将若干个连续且颜色相同的位置变成另外一种相同的颜色,求将整个序列变成同一种颜色最少步数。

题解

经典区间Dp,首先将相同颜色的连续块缩起来, f l , r f_{l,r} fl,r表示将 [ l , r ] [l,r] [l,r]变成同一种颜色的最少步数,考虑最后一步是怎么干的,一定有某种最优方案的最后一步是把整个区间变成 a l a_l al a r a_r ar的颜色(否则交换一下操作序列)。如果 a l ≠ a r a_l \neq a_r al̸=ar要么把 [ l + 1 , r ] [l+1,r] [l+1,r]变成 l l l的颜色,要么把 [ l , r − 1 ] [l,r-1] [l,r1]变成 r r r的颜色。否则的话还可以将 [ l + 1 , r − 1 ] [l+1,r-1] [l+1,r1]变成 a l , a r a_l,a_r al,ar的颜色。写个区间Dp即可。

代码
#include<bits/stdc++.h>
const int N = 5e3 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int f[N][N], c[N], n;
int main() {
	n = ri(); int _n = 0;
	for(int i = 1;i <= n; ++i) {
		c[i] = ri();
		if(c[i] != c[i - 1])
			c[++_n] = c[i];
	}
	n = _n;
	for(int i = 1;i < n; ++i)
		f[i][i + 1] = 1;
	for(int L = 3;L <= n; ++L) 
		for(int l = 1; l <= n - L + 1; ++l) {
			int r = l + L - 1;
			f[l][r] = std::min(f[l][r - 1], f[l + 1][r]);
			if(c[l] == c[r]) f[l][r] = std::min(f[l][r], f[l + 1][r - 1]);
			++f[l][r];
		}
	printf("%d\n", f[1][n]);
	return 0;
}

Problem E:Arithmetic Progression

题意

交互题,给一个序列是由某个公差为正的整数等差数列打乱而来的,仅仅给你这个序列的长度,每次可询问 &gt; x &gt;x >x表示询问序列中时候有严格大于 x x x的数或 ? x ?x ?x表示询问序列中第 x x x个数,求首项和公差。询问次数不超过 60 60 60

题解

考场没时间想了 q w q qwq qwq &gt; x &gt;x >x明摆这让你二分求最大值,大概花了 30 30 30次,剩下的那个就是只能随机得到这个等差数列的某个数。相当于是给你 30 30 30个数让你求公差。显然唯一的限制只有公差必须是两个数差的因子。因此排序相邻两个数相减之后去 g c d gcd gcd即可。错误的概率题解有给,大概是 1 0 − 9 10^{-9} 109级别。

代码
#include<bits/stdc++.h>
const int N = 1e6 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int Rand() {return (rand() << 15) + rand();}
int n, tp, st[100], ok[N], mx, d, cnt = 60;
int main() {
	srand(time(0));
	n = ri();
	int L = -1e9, R = 1e9;
	for(;L <= R;) {
		int m = L + R >> 1;
		printf("> %d\n", m);
		fflush(stdout); --cnt;
		ri() ? L = m + 1 : (mx = m, R = m - 1);
	}
	for(int i = 1;cnt && i <= n; ++i, --cnt) {
		int x = Rand() % n + 1;
		for(;ok[x];) x = Rand() % n + 1;
		printf("? %d\n", x); ok[x] = true;
		fflush(stdout);
		st[++tp] = ri();
	}
	std::sort(st + 1, st + tp + 1);
	if(st[tp] != mx) st[++tp] = mx;
	for(int i = 1;i < tp; ++i)
		d = std::__gcd(d, st[i + 1] - st[i]);
	int mn = mx - d * (n - 1);
	printf("! %d %d\n", mn, d);
	fflush(stdout); 
	return 0;
}

Problem F:Please, another Queries on Array?

题意

区间乘法和询问某区间积的欧拉函数对 1 0 9 + 7 10^9+7 109+7去模。数大小不超过 300 300 300

题解

由定义式可以得到 ϕ ( n ) = n ∏ i k ( 1 − 1 p i ) \phi(n)=n\prod_i^k(1-\frac{1}{p_i}) ϕ(n)=nik(1pi1)
n n n用线段树直接维护,一共只有 60 60 60个质因子,套个 b i t s e t bitset bitset即可。

代码
#include<bits/stdc++.h>
#define ls p << 1
#define rs p << 1 | 1
const int N = 4e5 + 10, P = 1e9 + 7;
typedef std::bitset<63> BI;
bool vis[301];
BI t[N << 2], tgt[N << 2], nwt;
int s[N << 2], tgs[N << 2], pr[301], iv[301], a[N], tp, nws, n, q;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f  = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int add(int a, int b) {return a += b, a >= P ? a - P : a;}
int fix(int x) {return (x >> 31 & P) + x;}
int mul(int a, int b) {return 1LL * a * b % P;}
int Pow(int x, int k) {
	int r = 1;
	for(;k; x = mul(x, x), k >>= 1)
		if(k & 1)
			r = mul(r, x);
	return r;
}
void Pre(int N) {
	for(int i = 2;i <= N; ++i) {
		if(!vis[i])
			pr[tp++] = i;
		for(int j = 0;j < tp && i * pr[j] <= N; ++j) {
			vis[i * pr[j]] = true;
			if(!(i % pr[j])) break;
		}
	}
}
BI Div(int x) {
	BI c;
	for(int i = 0;i < tp; ++i)
		if(!(x % pr[i]))
			c[i] = true;
	return c;
}
void Tag(int p, int len, int f) {
	tgs[p] = mul(tgs[p], tgs[f]);
	tgt[p] |= tgt[f];
	s[p] = mul(s[p], Pow(tgs[f], len));
	t[p] |= tgt[f];
}
void Add(int p) {
	nws = mul(nws, s[p]);
	nwt |= t[p];
}
void Up(int p) {
	s[p] = mul(s[ls], s[rs]);
	t[p] = t[ls] | t[rs];
}
void Push(int p, int L, int m, int R) {
	Tag(ls, m - L + 1, p);
	Tag(rs, R - m, p);
	tgs[p] = 1; tgt[p].reset();
} 
void Build(int p, int L, int R) {
	tgs[p] = 1;
	if(L == R) {
		t[p] = Div(a[L]);
		s[p] = a[L];
		return ;
	}
	int m = L + R >> 1;
	Build(ls, L, m); Build(rs, m + 1, R);
	Up(p);
}
void Modify(int p, int L, int R, int st, int ed) {
	if(L == st && ed == R)
		return Tag(p, R - L + 1, 0);
	int m = L + R >> 1; Push(p, L, m, R);
	if(st <= m) Modify(ls, L, m, st, std::min(ed, m));
	if(ed > m) Modify(rs, m + 1, R, std::max(st, m + 1), ed);
	Up(p);
}
void Query(int p, int L, int R, int st, int ed) {
	if(L == st && ed == R)
		return Add(p);
	int m = L + R >> 1; Push(p, L, m, R);
	if(st <= m) Query(ls, L, m, st, std::min(ed, m));
	if(ed > m) Query(rs, m + 1, R, std::max(st, m + 1), ed);
}
int main() {
	Pre(300);
	iv[1] = 1;
	for(int i = 2;i <= 300; ++i)
		iv[i] = mul(iv[P % i], fix(- (P / i)));
	for(int i = 1;i <= 300; ++i)
		iv[i] = mul(iv[i], i - 1);
	n = ri(); q = ri();
	for(int i = 1;i <= n; ++i)
		a[i] = ri();
	Build(1, 1, n);
	for(;q--;) {
		char op = getchar(); for(;op != 'T' && op != 'M'; op = getchar()) ;
		if(op == 'T') {
			int l = ri(), r = ri();
			nws = 1; nwt.reset();
			Query(1, 1, n, l, r);
			for(int i = 0;i < tp; ++i)
				if(nwt[i])
					nws = mul(nws, iv[pr[i]]);
			printf("%d\n", nws);
		}
		else {
			int l = ri(), r = ri();
			tgs[0] = ri(); tgt[0] = Div(tgs[0]);
			Modify(1, 1, n, l, r);
		}
	}
	return 0;
}

线段树打得不够溜啊 q w q qwq qwq,最后一题如果切的稍微快一点倒二就有机会想出来惹。。。不过。。。。我也是第一次在 C F CF CF上交交互题T_T,果然是太菜了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值