A 序列那么长
题目大意
给定一个序列,求前缀和/前缀积的奇偶性
分析
水题
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
int x;
int sum, mul=1;
int main()
{
int n;
cin>>n;
for (int i = 1; i <= n; i++)
{
cin>>x;
if (x < 0)
x = -x;
x &= 1;
sum = (sum+x)&1;
mul &= x;
cout<<sum<<mul<<endl;
}
return 0;
}
B gcd
题目大意
给定一个序列 { a n } \{a_n\} {an},给每个数都加上一个整数 x x x,求 max gcd { a n } \max\gcd\{a_n\} maxgcd{an}
分析
设能达到的 gcd \gcd gcd为 g g g,那么 { a n } \{a_n\} {an}在模 g g g意义下显然必须相等,于是各元素差的最大公因数即可。特判一下若整个数列相等,那么结果为 inf \inf inf
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int gcd(int x, int y)
{
if (!x)
return y;
if (!y)
return x;
if (x < y)
return gcd(y, x);
return gcd(y, x%y);
}
#define N 1000006
int n;
int arr[N];
int main()
{
cin.sync_with_stdio(false);
cin.tie(nullptr);
cin>>n;
bool inf = true;
for (int i = 1; i <= n; i++)
{
cin>>arr[i];
if (arr[i] != arr[1])
inf = false;
}
if (inf)
{
cout<<"inf";
return 0;
}
sort(arr+1, arr+n+1);
int g;
for (int i = 1; i < n; i++)
{
arr[i] = arr[i+1] - arr[i];
if (i==1)
g = arr[i];
else
g = gcd(g, arr[i]);
}
cout<<g;
return 0;
}
C 区间图与树
题目大意
给定 n n n个顶点,每个顶点是一个区间 [ i , j ] [i,j] [i,j],两顶点有边相连 ⟺ \iff ⟺两区间相交。问图是否是一个树
分析
首先不考虑数据出锅了导致这道题有特别简单的错误解法可以AC的情况。做的时候卡了好久,首先并查集是肯定的,但是时间复杂度 O ( n 2 ) O(n^2) O(n2)无情TLE了,然后考场上想到了用线段树去优化查找,由于坐标范围过大又需要上离散化——这当然是一种写法,只不过官方题解也说了比较麻烦。
实际上做的时候没意识到的是,先对区间排序,由于同侧端点的单调性,在对区间 x x x找它的相交区间时,这些区间一定是相邻的,这样保证(几乎)所有的访问一定是先找到相交区间。于是就可以保证 n − 1 n-1 n−1次成功访问就可以建立 n − 1 n-1 n−1条边,这样一旦建立 n n n条边就可以直接判定 N O NO NO,保证两重循环的时间复杂度是 O ( n ) O(n) O(n)。
然后数据的问题是没判森林:实际上两区间相交的话判断一下它们是否已经同属一个集合即可。在恰有 n − 1 n-1 n−1条边时,由于导致森林的不连通性的边一定多余存在于某个集合这种内部,这种不合法条件和森林是等价的。
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 1000006
typedef pair<int, int> P;
P arr[N];
int fa[N];
int n, m;
int father(int x)
{
if (!fa[x])
return fa[x] = x;
if (fa[x] == x)
return x;
else
return fa[x] = father(fa[x]);
}
void uni(int x, int y)
{
fa[father(x)] = father(y);
}
bool xj(int x, int y)
{
if (arr[x].first <= arr[y].first && arr[x].second >= arr[y].first
|| arr[y].first <= arr[x].first && arr[y].second >= arr[x].first)
return true;
return false;
}
int main()
{
cin>>n;
for (int i = 1; i <= n; i++)
{
int l, r;
cin>>l>>r;
arr[i] = make_pair(l, r);
}
sort(arr+1, arr+n+1, [](const P &lhs, const P &rhs) -> bool{
return rhs.second < lhs.second;
});
for (int i = 2; i <= n && m < n; i++)
{
for (int j = i-1; j >= 0; j--)
if (xj(i, j))
{
if (father(i) == father(j))
{
cout<<"NO";
return 0;
}
else
{
uni(i, j);
m++;
}
}
else
break;
}
if (m == n-1)
cout<<"YES";
else
cout<<"NO";
return 0;
}
做法2
本题做法还是挺多的,赛后说扫描线可以过,只不过赛场上看见 a i < 1 0 9 a_i<10^9 ai<109有点吓人就没敢写。