A题
给出PPP是一个大于5的质数,有Pmod a=Pmod b(2≤a<b≤P)P\mod a=P\mod b(2\leq a\lt b\leq P)Pmoda=Pmodb(2≤a<b≤P),找到任意一组a,ba,ba,b
- 显然Pmod 2=Pmod (P−1)=1P\mod 2=P\mod (P-1)=1Pmod2=Pmod(P−1)=1
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 100;
const double eps = 1e-6;
int main(){
int t, n;
cin >> t;
while(t--){
cin >> n;
cout << 2 << " " << n - 1 << '\n';
}
return 0;
}
B题
- 上面一行是敌人,如果是0只能由正下方的士兵到达,如果是1只能由左下方或者右下方的士兵到达
- 贪心策略枚举下面的每一个位置,如果是1,看上面,如果正上方是0,此位置士兵向上走最优;如果正上方不是0,先看左上再看右上,因为是从左面递推过来的
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 100;
const double eps = 1e-6;
int main(){
ios::sync_with_stdio(false);
int t, n;
string a, b;
cin >> t;
while(t--){
int ans = 0;
cin >> n;
cin >> a >> b;
vector<int> vis(n);
for(int i=0;i<n;i++){
if(b[i] == '0') continue;
if(a[i] == '0'){
ans++;
a[i] = '1';
vis[i] = 1;
}else{
if(i == 0){
if(!vis[i + 1] && a[i + 1] == '1'){
vis[i + 1] = 1;
ans++;
}
}else if(i == n - 1){
if(!vis[i - 1] && a[i - 1] == '1'){
vis[i - 1] = 1;
ans++;
}
}else{
if(!vis[i - 1] && a[i - 1] == '1'){
vis[i - 1] = 1;
ans++;
}else if(!vis[i + 1] && a[i + 1] == '1'){
vis[i + 1] = 1;
ans++;
}
}
}
}
cout << ans << '\n';
}
return 0;
}
C题
给出了一张图上的朋友关系,每个人的标号就是他的权重,如果一个人的所有朋友的权重都比他大,那么这个人在这一轮中会死亡,中间还可以进行加边和删边的操作,每次操作333询问当前状态下最后一轮还能剩多少人,每次操作333都是独立的
- 第一直觉和点的度数有关系。首先考虑一下,什么样的人会被杀呢?只要他有一个朋友的点权比他大,那么他就会被杀,也就是在连边之前如果点权小的度数为0,他就会被杀。考虑使用一个数组degreedegreedegree记录每条边具有较小点权的点的度数,初始存活人数为nnn,加边的时候,如果度数为0,那么n−1n-1n−1,度数加111,防止重复计算;删边的时候,较小点权的点的度数减111,如果减完发现度数为000,说明这个点变成了孤立点,存活下来,n+1n+1n+1
- 虽然每次操作333之间是独立的,但是边的改变是遗留下来的,所以答案保留
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 100;
const double eps = 1e-6;
int degree[MAXN];
int main(){
ios::sync_with_stdio(false);
int n, m, u, v, q, op;
cin >> n >> m;
int ans = n;
for(int i=0;i<m;i++){
cin >> u >> v;
if(u > v) swap(u, v);
if(degree[u] == 0){
ans -= 1;
}
degree[u] += 1;
}
cin >> q;
while(q--){
cin >> op;
if(op == 1){
cin >> u >> v;
if(u > v) swap(u, v);
if(degree[u] == 0) ans -= 1;
degree[u] += 1;
}else if(op == 2){
cin >> u >> v;
if(u > v) swap(u, v);
degree[u] -= 1;
if(degree[u] == 0) ans += 1;
}else{
cout << ans << '\n';
}
}
return 0;
}
D题
给出一个序列,让我们找某个子区间每一个数满足模mmm同余(m≥2)(m\geq2)(m≥2),问这个子区间最长是多少
- 如果aimod k=ajmod ka_i\mod k=a_j\mod kaimodk=ajmodk,那么有(ai−aj)=k×l(a_i-a_j)=k\times l(ai−aj)=k×l,且让找一个子区间,那么不难想到需要计算原序列的差分数组,同时此数组所有数都取绝对值便于判断GCDGCDGCD
- 那么可以枚举区间的左右端点,如果差分数组的某个区间内所有数的GCD≥2GCD\geq2GCD≥2,那么这个区间的长度可能就是答案,枚举所有这样的区间更新答案即可
- 所以需要高效维护数组的区间GCDGCDGCD,属于RMQRMQRMQ问题,可以考虑使用线段树或者STSTST表,这里就使用STSTST表了,使用一圈forforfor枚举区间右端点,再使用一个指针记录左端点,如果发现这个区间的GCD=1GCD=1GCD=1,那么左端点不停的右移直到到达右端点右侧(如果只是到达右端点在更新的时候会出现错误)或者发现GCD≠1GCD\neq 1GCD=1,继续移动右端点,重复操作更新答案
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e5 + 100;
const double eps = 1e-6;
ll ST[MAXN][50];
ll a[MAXN], b[MAXN];
int main(){
ios::sync_with_stdio(false);
int t, n;
cin >> t;
while(t--){
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
for(int i=1;i<n;i++){
b[i] = a[i + 1] - a[i];
ST[i][0] = abs(b[i]);
}
int sz = 31 - __builtin_clz(n);
for(int j=1;j<=sz;j++){
for(int i=1;i+(1 << (j - 1))<n;i++){
ST[i][j] = __gcd(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
}
}
int j = 1;
int ans = 1;
for(int i=1;i<n;i++){
int len = i - j + 1;
sz = 31 - __builtin_clz(len);
while(j <= i && __gcd(ST[j][sz], ST[i - (1 << sz) + 1][sz]) == 1){
j++;
len = i - j + 1;
sz = 31 - __builtin_clz(len);
}
ans = max(ans, i - j + 2);
}
cout << ans << '\n';
}
return 0;
}