2020牛客暑期多校第四场
H.Harder-Gcd-Problem
构造。除了1和大于n/2的质数,若剩下的数的个数为偶数则都能匹配,若为奇数则只有一个不能匹配。
从大到小考虑所有小于等于n/2的素数p,将未被访问的p的倍数加入集合,若集合大小为偶数,则恰好两两匹配,若集合大小为奇数,则取出p*2这个数(因为2是最后考虑的素数,所以p*2一定没有被访问过),剩下的两两匹配。最后把所有取出来的数再两两匹配一下(都是2的倍数)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int MAXN=2e5+5,mod=1e9+7;
int T,a,b,c,d,n,cnt;
int vis[MAXN],prime[MAXN],num_p;
int pfactor[MAXN];
void getPrime()
{
for (int i=2;i<MAXN;i++)
{
if (!vis[i]) prime[++num_p]=i;
for (int j=1;j<=num_p;j++)
{
if (i*prime[j]>=MAXN) break;
pfactor[i*prime[j]]=prime[j];
vis[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
}
bool visit[MAXN];
vector<pii>ans;
int main()
{
getPrime();
cin>>T;
while(T--)
{
cin>>n;
for (int i=1;i<=n;i++) visit[i]=0;
int p=1;
while(prime[p]<=n/2) p++;
p--;
vector<int>now;
vector<int>tot;
ans.clear();
for (int i=p;i>=1;i--)
{
now.clear();
for (int j=prime[i];j<=n;j+=prime[i])
{
if (!visit[j])
{
visit[j]=1;
now.push_back(j);
}
}
while(now.size()>3)
{
int x=now.back();
now.pop_back();
int y=now.back();
now.pop_back();
ans.push_back({x,y});
}
if (now.size()==3)
{
int x=now.back();
now.pop_back();
tot.push_back(now.back());
now.pop_back();
int y=now.back();
now.pop_back();
ans.push_back({x,y});
}
else
if (now.size()==2)
{
int x=now.back();
now.pop_back();
int y=now.back();
now.pop_back();
ans.push_back({x,y});
}
}
while(tot.size()>=2)
{
int x=tot.back();
tot.pop_back();
int y=tot.back();
tot.pop_back();
ans.push_back({x,y});
}
printf("%d\n",ans.size());
for (auto xx:ans) printf("%d %d\n",xx.first,xx.second);
}
return 0;
}
A.Ancient_Distance
dfs序+线段树维护子树
#include <bits/stdc++.h>
#define debug(x) cerr << #x << " : " << x << " "
#define debugl(x) cerr << #x << " : " << x << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 5;
int T, n, dp[N], dep[N], mxdep, ans[N], dfn[N], esc[N], id[N], idx, pre[N][25];
ll sum;
vector<int> G[N];
vector<pii> rb;
struct segment_tree{
#define lson ((o << 1))
#define rson ((o << 1) | 1)
#define mid ((l + r) >> 1)
int t[N << 4];
void pushup(int o) {
t[o] = max(t[lson], t[rson]);
}
void build(int o, int l, int r) {
if (l == r) {
t[o] = dep[l];
return;
}
build(lson, l, mid);
build(rson, mid + 1, r);
pushup(o);
}
int query(int o, int l, int r) {
if (l == r) return l;
if (t[lson] > t[rson]) return query(lson, l, mid);
else return query(rson, mid + 1, r);
}
void clean(int o, int l, int r, int tl, int tr) {
if (tl <= l && r <= tr) {
t[o] = 0;
return;
}
if (tl <= mid) clean(lson, l, mid, tl, tr);
if (tr > mid) clean(rson, mid + 1, r, tl, tr);
pushup(o);
}
void rollback(int o, int l, int r, int tl, int tr) {
if (tl <= l && r <= tr) {
if (l == r) t[o] = dep[l];
else pushup(o);
return;
}
if (tl <= mid) rollback(lson, l, mid, tl, tr);
if (tr > mid) rollback(rson, mid + 1, r, tl, tr);
pushup(o);
}
}st;
void dfs(int x, int f) {
dfn[x] = ++idx;
id[idx] = x;
dep[idx] = dp[x];
if (f != -1) pre[idx][0] = dfn[f];
mxdep = max(mxdep, dp[x]);
for (int to : G[x]) {
dp[to] = dp[x] + 1;
dfs(to, x);
}
esc[x] = idx;
}
int getans(int x) {
int res = 0;
while(1) {
int pos = st.query(1, 1, n);
int temp = x;
int k = 21;
while(temp) {
if (temp >= (1 << k)) {
temp -= 1 << k;
pos = pre[pos][k];
}
k--;
}
if (pos == 0 || pos == 1) {
reverse(rb.begin(), rb.end());
for (auto x : rb) st.rollback(1, 1, n, x.first, x.second);
rb.clear();
return res + 1;
}
st.clean(1, 1, n, pos, esc[id[pos]]);
rb.push_back({pos, esc[id[pos]]});
res++;
}
}
void init() {
for (int i = 1; i <= n; i++) {
G[i].clear();
}
sum = mxdep = idx = 0;
dp[1] = 1;
}
void solve() {
init();
for (int i = 1; i <= n - 1; i++) {
int x; scanf("%d", &x);
G[x].push_back(i + 1);
}
dfs(1, -1);
for (int i = 1; i <= 21; i++) {
for (int j = 1; j <= n; j++) pre[dfn[j]][i] = pre[pre[dfn[j]][i - 1]][i - 1];
}
st.build(1, 1, n);
for (int i = 0; i <= mxdep - 1; i++) {
if (i == 0) {
ans[i] = n;
continue;
}
ans[i] = getans(i);
sum += 1ll * (ans[i - 1] - ans[i]) * i;
}
printf("%lld\n", sum);
}
int main() {
while(~scanf("%d", &n)) solve();
return 0;
}