比赛传送门: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\)。
你有两种询问:
? i
(\(1\le i\le n\)):询问 \(a_i\) 的值,注意这里返回的是打乱后的。> 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\) 次操作,每次操作为以下两种之一:
MULTIPLY l r x
:将 \(a_l\) 到 \(a_r\) 之间(包括 \(a_l\) 和 \(a_r\))的所有数乘以 \(x\)。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;
}
原文地址:https://www.cnblogs.com/PinkRabbit/p/CF1114.html