Codeforces Round #736 (Div. 2)
A. Gregor and Cryptography
题目描述:
\(T\)组数据,每组数据给定一个质数\(P(5≤P≤10^9)\),求一组\(a\)和\(b(2≤a<b≤P)\),使得\(P\)%\(a=P\)%\(b\)。
思路:
因为\(P\)是大于\(5\)的质数,所以\(P\)一定是奇数。
考虑余数为\(1\)的情况,因为\(P\)是质数,所以一定没有\(2~P-1\)中的因数,那么就可以选\(P-1\)使得余数为1。
另一个就可以选择\(\frac{P-1}{2}\),因为\(P\)一定是奇数,所以\(P-1\)一定是偶数,又知道\(P\)%\(P-1=1\),因此\(P\)%\(\frac{P-1}{2}\)也一定等于\(1\)。
Code:
#include <bits/stdc++.h>
#define int long long
#define r(x) scanf("%lld", &x)
#define p(x) printf("%lld", x)
using namespace std;
void F() {
int p;
r(p);
if (p & 1)
cout << min(p - 1, (p - 1) / 2) << " " << max(p - 1, (p - 1) / 2) << endl;
else
cout << 2 << " " << p / 2 << endl;
}
main() {
int t;
r(t);
while (t--) F();
return 0;
}
B. Gregor and the Pawn Game
题目描述:
在一个\(N×N(1≤N≤2×10^5)\)的棋盘,我方有一棋子在第\(N\)排,对手有一些棋子在第\(1\)排,给定第一排和第\(N\)排的摆放方式(其中\(1\)为棋子,\(0\)为空位置),每个卒当上方为空位置时可以向上,当斜左方或斜右方有地方旗子时可以吃掉该棋子。问最多有多少个我方棋子到达第\(1\)排。
思路:
其实并不要考虑\(N×N\)这么大的规模,可以直接将\(N×N\)的棋盘压缩成\(2×N\)的棋盘。
对于我方棋子有\(3\)种方式可以到达终点:
- 上方为\(0\)时,直接到达终点。
- 斜左方为\(1\)时,吃掉对方棋子并到达终点。
- 斜右方为\(1\)时,吃掉对方棋子并到达终点。
直接模拟即可。
Code:
#include <bits/stdc++.h>
#define int long long
#define max(a, b) a > b ? a : b
#define min(a, b) a < b ? a : b
#define r(x) scanf("%lld", &x)
#define p(x) printf("%lld\n", x)
#define repo(i, x, y) for (int i = x; i <= y; i ++ )
#define repr(i, x, y) for (int i = x; i >= y; i -- )
const int N = 2e5 + 10;
int n;
bool flag[N];
char str1[N], str2[N];
void F()
{
r(n);
scanf("%s%s", str1 + 1, str2 + 1);
str1[n + 1] = '0';
memset(flag, false, sizeof flag);
flag[0] = 1, flag[n + 1] = 1;
int res = 0;
repo(i, 1, n)
{
if (str1[i] == '0' && str2[i] == '1') res ++ ;
else if (str1[i] == '1' && str2[i] == '1')
{
if (!flag[i - 1] && str1[i - 1] == '1') flag[i - 1] = 1, res ++ ;
else if(!flag[i + 1] && str1[i + 1] == '1') flag[i + 1] = 1, res ++ ;
}
}
p(res);
}
main()
{
int T;
r(T);
repr(i, T, 1) F();
return 0;
}
C. Web of Lies
题目描述:
有\(N(1≤N≤2×10^5)\)个人,\(M(0≤M≤2×10^5)\)个朋友关系,点\(i\)的权利为\(i\),当点\(i\)有朋友,且朋友的权力都比点\(i\)大时,点\(i\)会“自杀”。
给定\(3\)种操作:
- 将点\(x\)和点\(y\)设为朋友。(插入)
- 将点\(x\)和点\(y\)的朋友关系取消。(删除)
- 查询存活点的数量。(查询)
思路:
暴力的话肯定会超时。
那么我们考虑如何优化。
不难发现,如果\(x\)“自杀”,当且仅当权力最小的朋友比\(x\)的权力大。
明白这点后,我们就只需维护当前点所有朋友的最小值。
考虑插入和删除什么时候会对答案造成影响。
插入时:只有当\(y\)是\(x\)的第一个朋友,且\(x<y\)时,\(x\)一定会“自杀”,存活人数减\(1\)。
删除时:只有当\(y\)是\(x\)唯一的朋友,且\(x<y\)时,\(x\)会取消“自杀”,存活人数加\(1\)。
初始化:因为所有人都没有朋友,所以存活人数为\(N\)。
Code:
#include <bits/stdc++.h>
#define int long long
#define max(a, b) a > b ? a : b
#define min(a, b) a < b ? a : b
#define swap(a, b) (a ^= b ^= a ^= b)
#define r(x) scanf("%lld", &x)
#define p(x) printf("%lld\n", x)
#define repo(i, x, y) for (int i = x; i <= y; i ++ )
#define repr(i, x, y) for (int i = x; i >= y; i -- )
using namespace std;
const int N = 2e5 + 10;
int n, m, q, res;
set<int> st[N];
void add(int x, int y)
{
if (x > y) swap(x, y);
if (st[x].empty()) res -- ;
st[x].insert(y);
return;
}
void remove(int x, int y)
{
if (x > y) swap(x, y);
st[x].erase(y);
if (st[x].empty()) res ++ ;
return;
}
main()
{
r(n), r(m);
res = n;
repo(i, 0, m - 1)
{
int x, y;
r(x), r(y);
add(x, y);
}
r(q);
repr(i, q, 1)
{
int op;
r(op);
if (op == 1)
{
int u, v;
r(u), r(v);
add(u, v);
}
else if (op == 2)
{
int u, v;
r(u), r(v);
remove(u, v);
}
else p(res);
}
return 0;
}
D. Integers Have Friends
题目描述:
给定一个长为\(N(1≤N≤2×10^5)\)的序列\(a_1,a_2,...a_n(1≤a_i≤10^{18})\),任意选择一个\(m(m≥2)\)使得选择连续的一段满足\(a_imodm=a_{i+1}modm=...=a_jmodm\),求最大长度。
思路:
不难看出,要求出\(gcd\)才能满足条件,可是如果只在\(a\)序列上求\(gcd\)那么就只能求出\(m=0\)的情况。
在这里,我们提出一个命题:
如果\(gcd(|a_{i+1}-a_i|,...|a_j-a_{j-1}|)>1\)当且仅当\(a_imodm=a_{i+1}modm=...=a_jmodm\)时成立。
证明:设\(a_i=k_im+r\),\(a_{i+1}=k_{i+1}m+r\),\(b_i=|a_{i+1}-a_i|\)
那么,原式\(=gcd(b_i,...,b_j)\)
\(∵b_i=|a_{i+1}-a_i|=|k_{i+1}m+r-(k_{i+1}m+r)|=|k_{i+1}-k_i|m\)
\(∴b_i≡0(modm)\)
同理,\(b_{i+1}≡0(modm),...,b_j≡0(modm)\)
\(∴gcd(b_i,...,b_j)=m\)
又\(∵m≥2\)
\(∴\)原命题成立
那么,我们只需要\(ST\)表维护差值的最大公约数即可。
Code:
#include <bits/stdc++.h>
#define int long long
#define swap(a, b) (a ^= b ^= a ^= b)
#define r(x) scanf("%lld", &x)
#define p(x) printf("%lld\n", x)
#define rep(i, x, y) for (int i = x; i <= y; i ++ )
#define dec(i, x, y) for (int i = x; i >= y; i -- )
using namespace std;
const int N = 2e5 + 10;
int n;
int a[N], b[N];
int lg[N], f[N][21];
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int query(int x, int y) {
if (x > y) swap(x, y);
int k = lg[y - x + 1];
return gcd(f[y][k], f[x + (1 << k) - 1][k]);
}
void F()
{
r(n);
rep(i, 1, n) r(a[i]);
rep(i, 2, n) b[i - 1] = abs(a[i] - a[i - 1]);
rep(i, 1, n - 1)
{
f[i][0] = b[i];
rep(j, 1, 20)
if (i - (1 << (j - 1)) >= 0) f[i][j] = gcd(f[i][j - 1], f[i - (1 << (j - 1))][j - 1]);
}
int res = 0, r = 1;
rep(i, 1, n - 1)
{
r = max(r, i);
while (r + 1 <= n - 1 && query(i, r + 1) > 1)
r ++ ;
if (r == i && b[i] == 1) continue;
res = max(res, r - i + 1);
}
printf("%lld\n", res + 1);
}
main()
{
rep(i, 2, N - 1) lg[i] = lg[i >> 1] + 1;
int T;
r(T);
dec(i, T, 1) F();
return 0;
}

浙公网安备 33010602011771号