zoukankan      html  css  js  c++  java
  • 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) 个元素,求一种分割方案使得总贡献最大。

    题解:

    把最大的 (mcdot 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
    ", 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)。((1le nle 10^{18})(2le ble 10^{12})

    题解:

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

    对于 (b=p) 是质数的情况,数论告诉我们有:(v_p(n)=sum_{i=1}^{infty}lfloorfrac{n}{p^i} floor=lfloorfrac{n}{p} floor+lfloorfrac{n}{p^2} floor+lfloorfrac{n}{p^3} floor+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(leftlfloorfrac{v_{p_i}(n)}{e_i} ight floor ight) ]

    对于 (v_p(n)) 可以用这个方法计算:(v_p(n)=egin{cases}0&,n=0\lfloorfrac{n}{p} floor+v_p(lfloorfrac{n}{p} floor)&,n>0end{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
    ", 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+egin{cases}min(mathrm{f}[i+1][j],mathrm{f}[i][j-1])&,c[i] e 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
    ", f[1][N]);
    	return 0;
    }
    

    【E】Arithmetic Progression

    题意简述:

    这是一道交互题。

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

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

    你有两种询问:

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

    2. > x(0le xle 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 imes 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
    ", mid - 1);
    		fflush(stdout);
    		scanf("%d", &x);
    		++cnt;
    		if (x) mx = mid, l = mid + 1;
    		else r = mid - 1;
    	}
    	while (cnt < 60) {
    		printf("? %d
    ", Mran(1, N));
    		fflush(stdout);
    		scanf("%d", &x);
    		++cnt;
    		d = std::__gcd(d, mx - x);
    	}
    	printf("! %d %d
    ", 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) 的欧拉函数值。

    数据范围:(1le lle rle nle 4cdot 10^5)(1le qle 2cdot 10^5)(1le a_i,xle 300)

    题解:

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

    注意到 (a_i)(x) 很小,不超过 (300)
    又有 (varphi(x)=xprod_{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
    ", Ans);
    		}
    		else scanf("%d", &x), Mdf(Root, l, r, E[x], S[x]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    第十二周学习进度条
    寻找水王
    第十一周进度条
    第十周进度条
    构建之法阅读笔记(二)
    第九周学习进度
    团队名字
    站立会议09
    站立会议08
    站立会议07
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/CF1114.html
Copyright © 2011-2022 走看看