Codeforces Round #675 (Div. 2)、Codeforces Round #676 (Div. 2)
Codeforces Round #675 (Div. 2)、Codeforces Round #676 (Div. 2)
A. XORwice
已知 a , b a, b a,b,对于任意的 x x x,计算 ( a ⊕ x ) + ( b ⊕ x ) (a\oplus x)+(b\oplus x) (a⊕x)+(b⊕x)的最小值。
a | b | x | x | sum | sum |
---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 2 |
0 | 1 | 0 | 1 | 1 | 1 |
1 | 0 | 0 | 1 | 1 | 1 |
1 | 1 | 0 | 1 | 2 | 0 |
对于 a a a、 b b b的任意一位,只有当 a a a、 b b b的该位同时为 1 1 1的时候 x x x的该位为 1 1 1才能让该位的和比 x x x的该位为 0 0 0的时候小。
# include <iostream>
# include <cstdio>
void solve() {
int a, b;
scanf("%d%d", &a, &b);
int x = a & b;
int ans = (a ^ x) + (b ^ x);
printf("%d\n", ans);
}
int main() {
int T;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
另外,位运算中还有一个公式:
a
+
b
=
a
⊕
b
+
(
a
&
b
)
∗
2
a+b=a\oplus b +(a \&b) * 2
a+b=a⊕b+(a&b)∗2
此公式中的+
代表加法,*
代表乘法
证明:二进制计算中,
0
+
0
=
0
0+0=0
0+0=0,
0
+
1
=
1
0+1=1
0+1=1,
1
+
0
=
1
1+0=1
1+0=1,
1
+
1
=
0
′
1+1=0'
1+1=0′,但
1
+
1
=
0
1+1=0
1+1=0需要向高位进一位,相当于加上
(
a
&
b
)
<
<
1
(a\&b)<<1
(a&b)<<1。
另外,如果
a
+
b
≥
(
a
&
b
)
∗
2
a+b\ge (a\&b)*2
a+b≥(a&b)∗2并且
a
⊕
b
a\oplus b
a⊕b的每一个二进制位都和
a
&
b
a\&b
a&b不同时为1,那么
a
⊕
b
=
a
+
b
−
(
a
&
b
)
∗
2
a\oplus b=a+b-(a\&b)*2
a⊕b=a+b−(a&b)∗2。
B. Putting Bricks in the Wall
给定一个由
0
0
0和
1
1
1构成的
n
×
n
n×n
n×n的矩阵,有一个人从起点
(
1
,
1
)
(1,1)
(1,1)走到终点
(
n
,
n
)
(n, n)
(n,n),他只能够走相同的数字,要么全部路过元素为
1
1
1的格子,要么全部路过元素为
0
0
0的格子。
现最多给两次操作,每一次操作可以选择该数组的一个元素(除了起点和终点以外)从
0
0
0变成
1
1
1,也可以选择该数组的一个元素从
1
1
1变成
0
0
0。在操作后使得走迷宫的人不能走到终点。输出任意一种方案。
S | A | ||
---|---|---|---|
B | |||
D | |||
C | F |
只需要将A,B,C,D中的AB全变为0,CD全变为1,或者AB全变为1,CD全变为0即可。
# include <iostream>
# include <cstdio>
const int N = 205;
char a[N][N];
void solve() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%s", a[i] + 1);
}
int A, B, C, D;
A = a[1][2] - '0';
B = a[2][1] - '0';
C = a[n][n-1] - '0';
D = a[n-1][n] - '0';
int num = (A << 3) + (B << 2) + (C << 1) + D;
switch (num) {
case 0: {
printf("2\n1 2\n2 1\n");
break;
}
case 1: {
printf("1\n%d %d\n", n, n-1);
break;
}
case 2: {
printf("1\n%d %d\n", n-1, n);
break;
}
case 3: {
puts("0");
break;
}
case 4: {
printf("1\n1 2\n");
break;
}
case 5: {
printf("2\n2 1\n%d %d\n", n, n-1);
break;
}
case 6: {
printf("2\n2 1\n%d %d\n", n-1, n);
break;
}
case 7: {
printf("1\n2 1\n");
break;
}
case 8: {
printf("1\n2 1\n");
break;
}
case 9: {
printf("2\n2 1\n%d %d\n", n - 1, n);
break;
}
case 10: {
printf("2\n1 2\n%d %d\n", n - 1, n);
break;
}
case 11: {
printf("1\n1 2\n");
break;
}
case 12: {
printf("0\n");
break;
}
case 13: {
printf("1\n%d %d\n", n-1, n);
break;
}
case 14: {
printf("1\n%d %d\n", n, n-1);
break;
}
case 15: {
printf("2\n1 2\n2 1\n");
break;
}
}
}
int main() {
int T;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
C. Palindromifier
有一个仅由英文小写字母组成的长度为
n
n
n的字符串
s
s
s,对该字符串进行
k
k
k操作,每次操作可以选择以下两种操作中的一种:
操作
L
L
L:选择一个下标
i
(
2
≤
i
≤
n
−
1
)
i(2\le i\le n-1)
i(2≤i≤n−1),将
s
2
s
3
.
.
.
s
i
s_2s_3...s_i
s2s3...si复制(append)下来,然后倒置,再将其放到字符串的开头。
操作
R
R
R:选择一个下标
i
(
2
≤
i
≤
n
−
1
)
i(2\le i\le n-1)
i(2≤i≤n−1),将
s
i
s
i
+
1
.
.
.
s
n
−
1
s_is_{i+1}...s_{n-1}
sisi+1...sn−1复制(append)下来,然后倒置,再将其放到字符串的末尾。
0
≤
k
≤
30
0\le k \le30
0≤k≤30,目标是将字符串转为回文串。输出任意一种情况均可。
假设字符串是
a
b
c
d
e
abcde
abcde,经过
L
n
L\ n
L n的操作后会变成
d
c
b
a
b
c
d
e
dcbabcde
dcbabcde。这个字符串除了
e
e
e以外其余都是对称的。如果先将原字符串
a
b
c
d
e
abcde
abcde经过
R
n
−
1
R\ n-1
R n−1操作后变成
a
b
c
d
e
d
abcded
abcded,再经过
L
n
L\ n
L n的操作得到
e
d
c
b
a
b
c
d
e
d
edcbabcded
edcbabcded,再经过
L
2
L\ 2
L 2就可以得到
d
e
d
c
b
a
b
c
d
e
d
dedcbabcded
dedcbabcded,这是一个回文字符串。其余的字符串也能通过此方法得到回文字符串。
答案就是
3
R n-1
L n
L 2
# include <iostream>
# include <string>
int main() {
std::string s;
std::cin >> s;
int n = s.size();
std::cout << "3\nR " << n - 1 << "\nL " << n << "\nL 2";
return 0;
}
D. Hexagons
有一个正六边形构成的蜂窝网,每一个正六边形对应一个坐标,坐标的表示形式如图所示。
共有6个方向向量
C
1
(
1
,
1
)
C_1(1, 1)
C1(1,1),
C
2
(
0
,
1
)
C_2(0,1)
C2(0,1),
C
3
(
−
1
,
0
)
C_3(-1,0)
C3(−1,0),
C
4
(
−
1
,
−
1
)
C_4(-1,-1)
C4(−1,−1),
C
5
(
0
,
−
1
)
C_5(0,-1)
C5(0,−1),
C
6
(
1
,
0
)
C_6(1,0)
C6(1,0),每个方向向量有一个权重,代表往该方向走的花费。求从起点
(
0
,
0
)
(0,0)
(0,0)到终点
(
x
,
y
)
(x,y)
(x,y)的最小花费。
从原点到任意一点的最短路线仅仅只需要使用两个方向向量若干次。证明:假设目标点在原点的右边(在其他方向的证明过程也类似。),那么只需要 C 1 C_1 C1、 C 2 C_2 C2、 C 3 C_3 C3就可以到达该目标点,如果使用 C 4 C_4 C4、 C 5 C_5 C5、 C 6 C_6 C6就会和 C 1 C_1 C1、 C 2 C_2 C2、 C 3 C_3 C3相抵消,只会增加距离。而 C 2 C_2 C2刚好等于先走一步 C 1 C_1 C1再走一步 C 3 C_3 C3,因此如果 C 1 + C 3 < C 2 C_1+C_3 < C_2 C1+C3<C2那么就在需要走 C 2 C_2 C2时换成走一步 C 1 C_1 C1再走一步 C 3 C_3 C3,如果 C 1 + C 3 ≥ C 2 C_1+C_3 \ge C_2 C1+C3≥C2那么就在 C 1 C_1 C1和 C 3 C_3 C3都存在时将 C 1 C_1 C1和 C 3 C_3 C3替换成 C 2 C_2 C2,那么就只需要若干步 C 1 C_1 C1和若干步 C 2 C_2 C2 或者 若干步 C 3 C_3 C3和若干步 C 2 C_2 C2就可以以最少的代价到达目标点。
假设目标点的坐标为
(
x
,
y
)
(x, y)
(x,y),需要选择的方向向量为
(
i
x
,
i
y
)
(i_x,i_y)
(ix,iy)和
(
j
x
,
j
y
)
(j_x,j_y)
(jx,jy),需要走
k
1
k_1
k1步的
i
i
i和
k
2
k_2
k2步的
j
j
j,那么
(
x
,
y
)
=
k
1
∗
(
i
x
,
i
y
)
+
k
2
∗
(
j
x
,
j
y
)
(x,y)=k_1*(i_x,i_y)+k_2*(j_x,j_y)
(x,y)=k1∗(ix,iy)+k2∗(jx,jy)
{ x = k 1 ∗ i x + k 2 ∗ j x y = k 1 ∗ i y + k 2 ∗ j y \left\{ \begin{aligned} x = k_1*i_x+k_2*j_x \\ y=k1*i_y+k2*j_y \end{aligned} \right. {x=k1∗ix+k2∗jxy=k1∗iy+k2∗jy
k 1 = ∣ x j x y j y ∣ ∣ i x j x i y j y ∣ k 2 = ∣ x j x y j y ∣ ∣ i x j x i y j y ∣ k_1=\frac{\left|\begin{array}{cccc} x & j_x \\ y & j_y \end{array}\right| }{\left|\begin{array}{cccc} i_x & j_x \\ i_y & j_y \end{array}\right| }\quad k_2=\frac{\left|\begin{array}{cccc} x & j_x \\ y & j_y \end{array}\right| }{\left|\begin{array}{cccc} i_x & j_x \\ i_y & j_y \end{array}\right| } k1=∣∣∣∣ixiyjxjy∣∣∣∣∣∣∣∣xyjxjy∣∣∣∣k2=∣∣∣∣ixiyjxjy∣∣∣∣∣∣∣∣xyjxjy∣∣∣∣
枚举所有可以选择的方向向量对,删除方向相反的方向向量对,删除 ∣ i x j x i y j y ∣ = 0 \left|\begin{array}{cccc} i_x & j_x \\ i_y & j_y \end{array}\right|=0 ∣∣∣∣ixiyjxjy∣∣∣∣=0的方向向量对,删除 k 1 k_1 k1或 k 2 k_2 k2小于 0 0 0的方向向量对,剩下的所有方案中选最小值。
# include <iostream>
typedef long long ll;
const int dx[6] = {1, 0, -1, -1, 0, 1};
const int dy[6] = {1, 1, 0, -1, -1, 0};
int weight[6];
void solve() {
int x, y;
scanf("%d%d", &x, &y);
for (int i = 0; i < 6; i++) {
scanf("%d", &weight[i]);
}
ll min = 4e18;
for (int i = 0; i < 6; i++) {
for (int j = i + 1; j < 6; j++) {
if (j - i == 3) {
continue;
}
int delta = dx[i] * dy[j] - dx[j] * dy[i];
if (delta == 0) {
continue;
}
int delta_a = x * dy[j] - dx[j] * y;
int k1 = delta_a / delta;
int delta_b = y * dx[i] - dy[i] * x;
int k2 = delta_b / delta;
if (k1 < 0 || k2 < 0) {
continue;
}
ll ans = 1ll * k1 * weight[i] + 1ll * k2 * weight[j];
min = std::min(min, ans);
}
}
printf("%lld\n", min);
}
int main() {
int T;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
A. Fence
给定三条边 a a a, b b b, c c c,求边长 d d d,使得 a a a、 b b b、 c c c、 d d d能够构成一个非退化四边形(non-degenerate simple quadrilateral)。非退化四边形指的是四边形的四个角没有0度或者180度的情况。
输出 m a x ( a , b , c ) max(a, b, c) max(a,b,c)~ ( a + b + c − 1 ) (a+b+c-1) (a+b+c−1)之间的任意一个值都可。
# include <iostream>
# include <cstdio>
# include <algorithm>
# include <ctime>
typedef long long ll;
int random() {
return (rand() << 15) | rand();
}
// [0, n)
int random(int n) {
return random() % n;
}
// [l, r)
int random(const int &l, const int &r) {
if (l == r) {
return l;
}
return l + random(r - l);
}
long long randomll() {
return ((long long)random() << 30) | random();
}
long long randomll(const long long &n) {
return randomll() % n;
}
long long randomll(const long long &l, const long long &r) {
if (l == r) {
return l;
}
return l + randomll(r - l);
}
long double randoml() {
return (long double)randomll() / (1ll << 60);
}
long double randoml(const long double &n) {
return randoml() * n;
}
long double randoml(const long double &l, const long double &r) {
return l + randoml(r - l);
}
void solve() {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
ll l = std::max(std::max(a, b), c);
ll r = 1ll * a + b + c;
ll ans = randomll(l, r);
printf("%lld\n", ans);
}
int main() {
int T;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
B. Nice Matrix
给定一个 n × m n×m n×m的矩阵,每一次操作可以将该矩阵内的一个元素+1或者-1,求最小操作次数使得该矩阵的每一行、每一列都变成回文序列。
如果矩阵的每一行、每一列都是回文序列,那么 a [ i ] [ j ] = a [ i ] [ m − j − 1 ] = a [ n − i − 1 ] [ j ] a[i][j]=a[i][m-j-1]=a[n-i-1][j] a[i][j]=a[i][m−j−1]=a[n−i−1][j]。对三个数进行+1或者-1的操作使得三个数相等,花费最小,最优的方法是另外两个数通过+1或者-1变成中位数的值。对矩阵的每一个元素都进行此操作,记录下每一次操作的花费,求和即是答案。
# include <iostream>
# include <cstdio>
# include <vector>
# include <algorithm>
typedef long long ll;
int a[105][105];
void solve() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
scanf("%d", &a[i][j]);
}
ll ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
std::vector<int> b;
b.push_back(a[i][j]);
b.push_back(a[i][m-j-1]);
b.push_back(a[n-i-1][j]);
std::sort(b.begin(), b.end());
a[i][j] = a[i][m - j - 1] = a[n - i - 1][j] = b[1];
ans += 1ll * b[2] - b[1] + b[1] - b[0];
}
}
printf("%lld\n", ans);
}
int main() {
int T;
std::cin >> T;
while (T--){
solve();
}
return 0;
}
C. Bargain
给定一个数字
n
(
1
≤
n
≤
1
0
1
0
5
)
n(1\le n\le 10^{10^5})
n(1≤n≤10105),求
n
n
n的所有子字符串的和(不含原子串,但包含空串)。
枚举每个字符,考虑这一位能够将答案的和增加多少。
该位可增加的值分为:删除的区间在该位之前的贡献和删除的区间在该位之后的贡献。
以左边的数字为高位,右边的数字为低位,从0开始计数。
删除的区间在该位之前的贡献为
s
[
i
]
∗
1
0
i
∗
(
n
−
i
)
∗
(
n
−
i
+
1
)
2
s[i]*10^i*\frac{(n-i)*(n-i+1)}{2}
s[i]∗10i∗2(n−i)∗(n−i+1)
删除的区间在该位之后的贡献为
i
∗
1
0
i
−
1
+
(
i
−
1
)
∗
1
0
i
−
2
+
.
.
.
+
2
∗
1
0
1
+
1
∗
1
0
0
i*10^{i-1}+(i-1)*10^{i-2}+...+2*10^1+1*10^0
i∗10i−1+(i−1)∗10i−2+...+2∗101+1∗100。
令
\quad \quad
S
(
n
)
=
1
∗
1
0
0
+
2
∗
1
0
1
+
.
.
.
+
(
n
−
1
)
∗
1
0
n
−
2
+
n
∗
1
0
n
−
1
S(n)=1*10^0+2*10^1+...+(n-1)*10^{n-2}+n*10^{n-1}
S(n)=1∗100+2∗101+...+(n−1)∗10n−2+n∗10n−1
\quad
10
∗
S
(
n
)
=
1
∗
1
0
1
+
.
.
.
+
(
n
−
2
)
∗
1
0
n
−
1
+
(
n
−
1
)
∗
1
0
n
−
1
+
n
∗
1
0
n
10*S(n)=\quad\quad \quad \quad1*10^1+...+(n-2)*10^{n-1}+(n-1)*10^{n-1}+n*10^n
10∗S(n)=1∗101+...+(n−2)∗10n−1+(n−1)∗10n−1+n∗10n
−
9
∗
S
(
n
)
=
1
∗
1
0
0
+
1
∗
1
0
1
+
.
.
.
+
1
∗
1
0
n
−
2
+
1
∗
1
0
n
−
1
−
n
∗
1
0
n
\quad-9*S(n)=1*10^0+1*10^1+...+1*10^{n-2}+1*10^{n-1}-n*10^n
−9∗S(n)=1∗100+1∗101+...+1∗10n−2+1∗10n−1−n∗10n
−
9
∗
S
(
n
)
=
1
0
n
−
1
9
−
n
∗
1
0
n
\quad-9*S(n)=\frac{10^n-1}{9}-n*10^n
−9∗S(n)=910n−1−n∗10n
S
(
n
)
=
(
9
∗
n
−
1
)
∗
1
0
n
+
1
81
S(n)=\frac{(9*n-1)*10^n+1}{81}
S(n)=81(9∗n−1)∗10n+1
在取模运算中,
(
a
+
b
)
%
p
=
(
a
%
p
+
b
%
p
)
%
p
(a+b)\%p=(a\%p+b\%p)\%p
(a+b)%p=(a%p+b%p)%p
此写法等价于
(
a
+
b
)
≡
(
a
%
p
+
b
%
p
)
(
m
o
d
p
)
(a+b)\equiv(a\%p+b\%p) (mod\ p)
(a+b)≡(a%p+b%p)(mod p)。这个写法叫做“同余”。
(
a
−
b
)
%
p
=
(
a
%
p
−
b
%
p
+
p
)
%
p
(a-b)\%p=(a\%p-b\%p+p)\%p
(a−b)%p=(a%p−b%p+p)%p
(
a
∗
b
)
%
p
=
(
a
%
p
∗
b
%
p
)
%
p
(a*b)\%p=(a\%p*b\%p)\%p
(a∗b)%p=(a%p∗b%p)%p
若
b
b
b与
p
p
p互质,
a
b
%
p
=
a
%
p
∗
b
ϕ
(
p
)
−
1
%
p
\frac{a}{b}\%p=a\%p*b^{\phi(p)-1}\%p
ba%p=a%p∗bϕ(p)−1%p。
b
ϕ
(
p
)
−
1
b^{\phi(p)-1}
bϕ(p)−1被称作
b
b
b的乘法逆元。也可以通过扩展欧几里得算法算出乘法逆元。
1 1 1~ n n n中与 n n n互质的数的个数叫做欧拉函数。记为 ϕ ( n ) \phi(n) ϕ(n)。当 n n n为质数时, ϕ ( n ) = n − 1 \phi(n)=n-1 ϕ(n)=n−1
int phi(n) {
int ans = n;
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) {
ans = ans / n * (n - 1);
}
return ans;
}
或者在main函数下的第一行使用init()函数求S[n]
int S[N];
void init() {
S[0] = 0;
S[1] = 1;
int p10 = 10;
for (int i = 2; i < N; i++) {
S[i] = (S[i-1] + 1ll * i * p10 % mod) % mod;
p10 = 1ll * p10 * 10 % mod;
}
}
# include <iostream>
# include <cstdio>
# include <string>
# include <algorithm>
typedef long long ll;
const int mod = 1e9 + 7;
int inv;
int qpow(int a, int b) {
int ans = 1 % mod;
while (b) {
if (b & 1) {
ans = 1ll * ans * a % mod;
}
b >>= 1;
a = 1ll * a * a % mod;
}
return ans;
}
int qsum(int n) {
if (n == 0) {
return 0;
}
int fz = 1ll * (9 * n - 1) * qpow(10, n) % mod + 1;
fz %= mod;
return 1ll * fz * inv % mod;
}
int main() {
inv = qpow(81, mod - 2);
std::string s;
std::cin >> s;
std::reverse(s.begin(), s.end());
int n = s.size() - 1;
ll ans = 0, p10 = 1;
for (int i = 0; i < s.size(); i++) {
int d = s[i] - '0';
ll sum1 = 1ll * (n - i) * (n - i + 1) / 2 % mod * p10 % mod * d % mod;
ll sum2 = 1ll * d * qsum(i) % mod;
ans = ((ans + sum1) % mod + sum2) % mod;
p10 = p10 * 10 % mod;
}
std::cout << ans << "\n";
return 0;
}
本文地址:https://blog.csdn.net/qq_43450413/article/details/109191141
推荐阅读
-
Codeforces Round #595 (Div. 3)D1D2 贪心 STL
-
Codeforces Round #655 (Div. 2) A. Omkar and Completion
-
Codeforces Round #656 (Div. 3)D. a-Good String(递归+dfs)
-
Codeforces Round #487 (Div. 2)
-
CodeForces 1324 - Codeforces Round #627 (Div. 3)
-
Codeforces Round #649 (Div. 2)-B. Most socially-distanced subsequence(思维)
-
Codeforces Round #649 (Div. 2) C-Ehab and Prefix MEXs
-
Educational Codeforces Round 71 (Rated for Div. 2)E. XOR Guessing
-
Codeforces Round #659 (Div. 2) A. Common Prefixes(字符串,思维)
-
Codeforces Round #610 (Div. 2)