目录
B Build Roads
题意
给定 n ( 1 ≤ n ≤ 2 ⋅ 1 0 5 ) n(1\leq n\leq2\cdot10^5) n(1≤n≤2⋅105)个点的完全图,每个点有一个权值为 a i ( 1 ≤ a i ≤ 2 ⋅ 1 0 5 ) a_i(1\leq a_i\leq2\cdot10^5) ai(1≤ai≤2⋅105),两个点 i i i和 j j j之间的边权为 g c d ( a i , a j ) gcd(a_i,a_j) gcd(ai,aj)。题目给定点权 a i a_i ai随机生成的程序、范围以及随机种子,要求该图的最小生成树。
题解
首先如果点权范围 L = = R L==R L==R,那么很容易得到答案 ( n − 1 ) ⋅ L (n-1)\cdot L (n−1)⋅L。
然后如果随机次数足够多,是很容易找到 n − 1 n-1 n−1对互质的权值,此时答案为 n − 1 n-1 n−1。
对于剩下的边数少的情况直接跑最小生成树。
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=2e5+10;
int n,L,R;
ull seed;
int a[maxn];
ull rand64(){
ull x=seed;
x^=x<<13;
x^=x>>7;
x^=x<<17;
return seed=x;
}
int gen(){
return rand64()%(R-L+1)+L;
}
int gcd(int x,int y){
if(x<y) swap(x,y);
return y?gcd(y,x%y):x;
}
struct node {
int u,v;
ll w;
bool operator < (const node & d) const {
return w>d.w;
}
};
priority_queue<node> q;
int rt[maxn];
int fi(int x){
return x==rt[x]?x:rt[x]=fi(rt[x]);
}
void solve(){
scanf("%d%d%d%llu",&n,&L,&R,&seed);
for(int i=1;i<=n;i++){
a[i]=gen();
}
if(L==R){
printf("%lld\n",1ll*L*(n-1));
}
else {
if(n>=1000) printf("%d\n",n-1);
else {
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
q.push({
i,j,gcd(a[i],a[j])});
}
}
ll ans=0;
for(int i=1;i<=n;i++) rt[i]=i;
while(!q.empty()){
int u=q.top().u,v=q.top().v;
ll w=q.top().w;
q.pop();
int fx=fi(u),fy=fi(v);
if(fx!=fy){
rt[fx]=fy;
ans+=w;
}
}
printf("%lld\n",ans);
}
}
}
int main(){
// freopen("in.txt","r",stdin);
solve();
return 0;
}
C Cat Virus
题意
给定一颗有根树,对每个节点进行黑白染色,要求如果一个点为黑色,则其子树节点必须均染为黑色。你需要构造一颗染色方案数为 K ( 1 ≤ K ≤ 2 ⋅ 1 0 18 ) K(1\leq K \leq 2\cdot10^{18}) K(1≤K≤2⋅1018