CodeForces Contest #1114: Round #538 (Div. 2)

比赛传送门:CF #1114

比赛记录:点我

又 FST 了。


【A】Got Any Grapes?

题意简述:

有三个人,第一个人需要吃绿色葡萄至少 \(a\) 个,第二个人需要吃绿色和紫色葡萄至少 \(b\) 个,第三个人需要吃绿色、紫色和黑色葡萄至少 \(c\) 个。
\(x\) 个绿色葡萄,\(y\) 个紫色葡萄,\(z\) 个黑色葡萄,问是否能够满足三个人的要求。

题解:

#include <cstdio>

int main() {
	int x, y, z, a, b, c;
	scanf("%d%d%d%d%d%d", &x, &y, &z, &a, &b, &c);
	if (a < x || a + b < x + y || a + b + c < x + y + z) puts("NO");
	else puts("YES");
	return 0;
}

【B】Yet Another Array Partitioning Task

题意简述:

一个长度为 \(n\) 的数组 \(a_i\),要把它分成 \(k\) 个连续段(每段长度大于等于 \(m\)),每段的贡献是其中最大的 \(m\) 个元素,求一种分割方案使得总贡献最大。

题解:

把最大的 \(m\cdot k\) 个数提取出来,暴力分割。

#include <cstdio>
#include <algorithm>

typedef long long LL;

int N, M, K;
int A[200005], B[200005];
LL Ans = 0;

int main(){
	scanf("%d%d%d", &N, &M, &K);
	for (int i = 1; i <= N; ++i) {
		scanf("%d", &A[i]);
		B[i] = i;
	}
	std::sort(B + 1, B + N + 1, [](int i, int j) { return A[i] > A[j]; });
	std::sort(B + 1, B + M * K + 1);
	for (int i = 1; i <= M * K; ++i) Ans += A[B[i]];
	printf("%lld\n", Ans);
	for (int i = M; i < M * K; i += M) printf("%d ", B[i]);
	puts("");
	return 0;
}

【C】Trailing Loves (or L'oeufs?)

题意简述:

\(n!\)\(n\) 的阶乘)在 \(b\) 进制下末尾有几个 \(0\)。(\(1\le n\le 10^{18}\)\(2\le b\le 10^{12}\)

题解:

相当于求最大的 \(k\) 使得 \(b^k|n!\)。记这个值为 \(v_b(n)\)

对于 \(b=p\) 是质数的情况,数论告诉我们有:\(v_p(n)=\sum_{i=1}^{\infty}\lfloor\frac{n}{p^i}\rfloor=\lfloor\frac{n}{p}\rfloor+\lfloor\frac{n}{p^2}\rfloor+\lfloor\frac{n}{p^3}\rfloor+\cdots\)

\(v_p(n)\) 给出了 \(n!\) 的标准分解式中 \(p^k\) 因子的次方数 \(k\)

这启发我们将 \(b\) 质因数分解:\(b=p_1^{e_1}p_2^{e_2}\cdots p_k^{e_k}\)

则有:

\[v_b(n)=\min_{i=1}^{k}\left(\left\lfloor\frac{v_{p_i}(n)}{e_i}\right\rfloor\right) \]

对于 \(v_p(n)\) 可以用这个方法计算:\(v_p(n)=\begin{cases}0&,n=0\\\lfloor\frac{n}{p}\rfloor+v_p(\lfloor\frac{n}{p}\rfloor)&,n>0\end{cases}\)

#include <cstdio>
#include <algorithm>

typedef long long LL;
const LL INF = 0x3f3f3f3f3f3f3f3f;

LL N, b;
LL p[25]; int e[25], cnt;
LL Ans = INF;

int main() {
	scanf("%lld%lld", &N, &b);
	for (LL i = 2; i * i <= b; ++i) if (b % i == 0) {
		p[++cnt] = i, e[cnt] = 0;
		while (b % i == 0) b /= i, ++e[cnt];
	} if (b > 1) p[++cnt] = b, e[cnt] = 1;
	for (int i = 1; i <= cnt; ++i) {
		LL num = 0, m = N;
		while (m) num += m / p[i], m /= p[i];
		Ans = std::min(Ans, num / e[i]);
	}
	printf("%lld\n", Ans);
	return 0;
}

【D】Flood Fill

题意简述:

一个长度为 \(n\) 的序列 \(c_1,c_2,\ldots,c_n\)

你可以选择一个位置 \(pos\),每次操作你把 \(pos\) 所在联通块全部变成一个数。
问最少花费几次操作可以把整个序列变成同一个数。

一个联通块指 \(c_i\) 全部相同的连续一段。

题解:

先把序列 unique 一下,得到联通块个数。

\(\mathrm{f}[i][j]\) 为把序列的第 \(i\) 位到第 \(j\) 位全部变成同一种颜色要花费的最小操作数。

转移:\(\mathrm{f}[i][j]=1+\begin{cases}\min(\mathrm{f}[i+1][j],\mathrm{f}[i][j-1])&,c[i]\ne c[j]\\\mathrm{f}[i+1][j-1]&,c[i]=c[j]\end{cases}\)

#include <cstdio>
#include <algorithm>

const int MN = 5005;

int N, c[MN];
int f[MN][MN];

int main() {
	scanf("%d", &N);
	for (int i = 1; i <= N; ++i)
		scanf("%d", &c[i]);
	N = std::unique(c + 1, c + N + 1) - c - 1;
	for (int i = 1; i <= N; ++i)
		f[i][i] = 0;
	for (int Q = 2; Q <= N; ++Q) {
		for (int i = 1; i <= N - Q + 1; ++i) {
			int j = i + Q - 1;
			if (c[i] == c[j]) f[i][j] = f[i + 1][j - 1] + 1;
			else f[i][j] = std::min(f[i + 1][j], f[i][j - 1]) + 1;
		}
	}
	printf("%d\n", f[1][N]);
	return 0;
}

【E】Arithmetic Progression

题意简述:

这是一道交互题。

交互器有一个长度为 \(n\)\(2\le n\le 10^6\))的等差数列 \(a_1,a_2,\ldots,a_n\)。保证 \(0\le a_i\le 10^9\),且公差 \(d=a_2-a_1>0\)

但是这个等差数列被随机打乱了,给定 \(n\),你需要做出不超过 \(60\) 次询问,得到 \(a_1\) 和公差 \(d\)

你有两种询问:

  1. ? i\(1\le i\le n\)):询问 \(a_i\) 的值,注意这里返回的是打乱后的。

  2. > x\(0\le x\le 10^9\)):询问这个等差数列中是否存在一个数 \(a_i\) 满足 \(a_i>x\)

题解:

首先使用不超过 \(30\) 次询问 > x,二分查找找到最大的数 \(max\)

\(d=0\)

然后使用若干次 ? i,这里 \(i\) 是在 \(1\)\(n\) 内等概率随机的,每次得到一个数 \(a_i\),令 \(d=\gcd(d,max-a_i)\)

最后 \(a_1=max-(n-1)d\)

为什么这样是正确的?显然找到最大的数的询问次数的确不超过 \(30\) 次。

接下来还有至少 \(60-30=30\) 次操作,用于更新公差 \(d\)
答案正确的可能性等价于在 \(0\)\(n-1\) 中等概率随机选取至少 \(30\) 个数,并且它们的 \(\gcd\) 等于 \(1\)
可以证明答案错误的概率小于 \(1.86\times 10^{-9}\)

注意选取合适的随机数生成器,无良出题人专门卡了普通的 rand()

#include <cstdio>
#include <algorithm>

inline unsigned Uran() {
	static unsigned x = 20021005;
	return x ^= x << 17, x ^= x >> 13, x ^= x << 5;
}
inline int Mran(int L, int R) {
	return Uran() % (R - L + 1) + L;
}

int N, cnt, d;

int main() {
	scanf("%d", &N);
	int l = N, r = 1e9, mid, x, mx = N - 1;
	while (l <= r) {
		mid = (l + r) >> 1;
		printf("> %d\n", mid - 1);
		fflush(stdout);
		scanf("%d", &x);
		++cnt;
		if (x) mx = mid, l = mid + 1;
		else r = mid - 1;
	}
	while (cnt < 60) {
		printf("? %d\n", Mran(1, N));
		fflush(stdout);
		scanf("%d", &x);
		++cnt;
		d = std::__gcd(d, mx - x);
	}
	printf("! %d %d\n", mx - (N - 1) * d, d);
	return 0;
}

【F】Please, another Queries on Array?

题意简述:

一个长度为 \(n\) 的序列 \(a_1,a_2,\ldots,a_n\)。有 \(q\) 次操作,每次操作为以下两种之一:

  1. MULTIPLY l r x:将 \(a_l\)\(a_r\) 之间(包括 \(a_l\)\(a_r\))的所有数乘以 \(x\)

  2. TOTIENT l r :询问 \(\varphi(\prod_{i=l}^{r}a_i)\pmod{10^9+7}\),其中 \(\varphi(x)\) 表示 \(x\) 的欧拉函数值。

数据范围:\(1\le l\le r\le n\le 4\cdot 10^5\)\(1\le q\le 2\cdot 10^5\)\(1\le a_i,x\le 300\)

题解:

首先想到使用线段树维护区间。

注意到 \(a_i\)\(x\) 很小,不超过 \(300\)
又有 \(\varphi(x)=x\prod_{p|x}\frac{p-1}{p}\),这提示我们维护区间乘积以及区间质因数集合。

发现 \(300\) 以内的质数个数只有 \(62\) 个,正好在 long long 的位数范围内,这提示我们状压集合存入 long long 中。

变成了基础线段树例题,复杂度 \(\mathrm{O}((n+q)\log^2 n)\)。使用原根化乘为加可以做到 \(\mathrm{O}((n+q)\log n)\)

这里给出使用原根和 BSGS 打表的代码,\(10^9+7\) 的原根是 \(5\)

#include <cstdio>
#include <algorithm>
#include <map>

typedef unsigned long long LL;
typedef std::pair<LL, LL> pll;
const LL Mod = 1000000007, eM = 1000000006, G = 5;
const int MX = 301;

inline LL qPow(LL b, int e) {
	LL a = 1;
	for (; e; e >>= 1, b = b * b % Mod)
		if (e & 1) a = a * b % Mod;
	return a;
}

const int E[MX] = {0, 0, 381838282, 884237698, 763676564, 1, 266075974, 936544532, 145514840, 768475390, 381838283, 649233168, 647914256, 144547565, 318382808, 884237699, 527353122, 895459693, 150313666, 701153241, 763676565, 820782224, 31071444, 82047235, 29752532, 2, 526385847, 652713082, 700221090, 347375814, 266075975, 198670980, 909191404, 533470860, 277297969, 936544533, 532151948, 289190395, 82991517, 28785257, 145514841, 802264261, 202620500, 24616936, 412909726, 768475391, 463885517, 730741137, 411590814, 873089058, 381838284, 779697385, 908224129, 616590335, 34551358, 649233169, 82059366, 585390933, 729214096, 178404868, 647914257, 234516540, 580509262, 705019916, 291029680, 144547566, 915309142, 351358075, 659136251, 966284933, 318382809, 557546595, 913990230, 559624399, 671028677, 884237700, 464829799, 585777694, 410623539, 414776906, 527353123, 536950774, 184102537, 809672376, 584458782, 895459694, 406455218, 231613506, 794748008, 689565125, 150313667, 81092091, 845723799, 82908672, 112579413, 701153242, 793429096, 993378125, 254927334, 417708552, 763676566, 495914368, 161535661, 991051336, 290062405, 820782225, 998428617, 326036185, 416389640, 525353314, 31071445, 173428087, 463897648, 429750477, 967229215, 82047236, 111052372, 913022955, 560243150, 832004219, 29752533, 298466330, 616354822, 686501953, 962347544, 3, 86858192, 155622902, 672867962, 908854634, 526385848, 26958408, 297147418, 637697767, 733196357, 652713083, 40974527, 540374100, 348123209, 293399235, 700221091, 614978829, 939384877, 793780733, 295828506, 347375815, 941462681, 757326750, 52866953, 109607515, 266075976, 468364065, 846668081, 663935077, 967615976, 198670981, 792461821, 967234449, 796615188, 500828027, 909191405, 18591761, 918789056, 238291131, 565940819, 533470861, 191510652, 98758628, 966297064, 289095130, 277297970, 469628625, 788293500, 328851128, 613451788, 936544534, 176586284, 62642560, 71403401, 492996069, 532151949, 546888614, 462930373, 118754232, 227562075, 289190396, 464746954, 544692855, 494417695, 589257608, 82991518, 366164793, 175267372, 23539458, 375216401, 28785258, 636765616, 829772542, 799546834, 912024915, 145514842, 235595767, 877752650, 283920340, 543373943, 802264262, 372889612, 850522625, 671900687, 350386403, 202620501, 437098732, 380266893, 441784287, 707874467, 24616937, 798227922, 135215506, 907191596, 443862091, 412909727, 40007252, 555266369, 768794522, 845735930, 768475392, 811588759, 342799273, 349067491, 566661897, 463885518, 470015386, 492890654, 924677391, 294861231, 730741138, 942081432, 299014598, 213842495, 732754158, 411590815, 733768720, 680304612, 421188466, 998193104, 873089059, 68340229, 845700806, 344185820, 693910068, 381838285, 241119035, 468696474, 731280403, 537461184, 779697386, 54706238, 17661842, 290692910, 225734921, 908224130, 115851198, 408796690, 872301485, 678985700, 616590336, 19536043, 573802817, 115034633, 298959763, 34551359, 462560014, 422812809, 965329789, 922212382, 649233170, 729961491, 31035300, 675237517, 967146370, 82059367, 345578910, 996817111, 82704431, 321223153, 585390934, 175619009, 738808787, 677666788, 790919380, 729214097, 877615817, 323300957, 912101836, 139165026, 178404869, 434705235, 301946244, 491445797, 226594800, 647914258};
int ip[MX], v[62], pc;
LL S[MX];

void Init(int N) {
	for (int i = 2; i <= N; ++i) if (!ip[i]) {
		for (int j = i; j <= N; j += i) {
			if (j > i) ip[j] = 1;
			S[j] |= 1llu << pc;
		}
		v[pc++] = (i - 1) * qPow(i, Mod - 2) % Mod;
	}
}
 
const int MS = 1 << 20 | 7;
#define li (i << 1)
#define ri (i << 1 | 1)
#define len (r - l + 1)
#define mid ((l + r) >> 1)
#define now i, l, r
#define ls li, l, mid
#define rs ri, mid + 1, r
#define Root 1, 1, N
#define St int i, int l, int r

LL sum[MS], st[MS], t1[MS], t2[MS];

inline void P(St, LL v, LL s) {
	sum[i] = (sum[i] + len * v) % eM, st[i] |= s;
	t1[i] = (t1[i] + v) % eM, t2[i] |= s;
}
inline void Pd(St) {
	if (t1[i] || t2[i]) {
		P(ls, t1[i], t2[i]), P(rs, t1[i], t2[i]);
		t1[i] = t2[i] = 0;
	}
}

void Mdf(St, int a, int b, LL v, LL s) {
	if (r < a || b < l) return ;
	if (a <= l && r <= b) return P(now, v, s);
	Pd(now);
	Mdf(ls, a, b, v, s), Mdf(rs, a, b, v, s);
	sum[i] = (sum[li] + sum[ri]) % eM;
	st[i] = st[li] | st[ri];
}

pll Qur(St, int a, int b) {
	if (r < a || b < l) return pll(0llu, 0llu);
	if (a <= l && r <= b) return pll(sum[i], st[i]);
	Pd(now);
	pll p1 = Qur(ls, a, b), p2 = Qur(rs, a, b);
	return pll((p1.first + p2.first) % eM, p1.second | p2.second);
}

int N, Q;

int main() {
	int x;
	Init(300);
	scanf("%d%d", &N, &Q);
	for (int i = 1; i <= N; ++i) {
		scanf("%d", &x);
		Mdf(Root, i, i, E[x], S[x]);
	}
	for (int q = 1; q <= Q; ++q) {
		char opt[9]; int l, r;
		scanf("%s%d%d", opt, &l, &r);
		if (*opt == 'T') {
			pll P = Qur(Root, l, r);
			LL Ans = qPow(G, P.first);
			for (int i = 0; i < pc; ++i)
				if (P.second >> i & 1) Ans = Ans * v[i] % Mod;
			printf("%llu\n", Ans);
		}
		else scanf("%d", &x), Mdf(Root, l, r, E[x], S[x]);
	}
	return 0;
}
posted @ 2019-02-23 23:35  粉兔  阅读(349)  评论(0编辑  收藏  举报