Build Roads
题意:
n个点,每个点的值为a[i],求最小生成树
a[i]是通过题目中给出的程序得到(即a[i]如何得到的我们并不需要很了解)
题解:
肯定不能直接跑最小生成树,因为数据太大了
银川也有个类似的题,比赛时我直接打表,发现当n很大时,答案就是n-1,通过我大量枚举,我得到结论,当n>1000时,我们就直接套结论,当小于1000时,就跑遍最小生成树
但是忘了一种情况,导致一直wa,题目给的L和R,表示的是a[i]的范围,如果L == R时(n很大),说明每个点的值都是L,那么gcd求出边长都是L,所以答案就是(n-1)*L
挺可惜,比赛时一直没想到最后这一小点
代码:
//蒟蒻三人行
#include<bits/stdc++.h>
#include<map>
#define random(a,b) ((a)+rand()%((b-a+1)))
typedef long long ll;
using namespace std;
const int maxn=1e7+9;
int n,L,R,a[200001];
int tot=0;
unsigned long long seed;
unsigned long long xorshift64()
{unsigned long long x=seed;x^=x<<13;x^=x>>7;x^=x<<17;return seed=x;
}
int gen(){return xorshift64()%(R-L+1)+L;
}
int gcd(int a,int b)
{if(b)return gcd(b,a%b);return a;
}
int fa[maxn];
struct node{int u,v,w;
}edge[maxn];
bool cmp(node a,node b)
{return a.w<b.w;
}
int find(int x)
{if(fa[x]==-1)return x;else return fa[x]=find(fa[x]);
}
ll kruskal(int n)
{memset(fa,-1,sizeof(fa));sort(edge+1,edge+1+tot,cmp);int cnt=0;ll ans=0;//cout<<tot<<endl;for(int i=1;i<=tot;i++){int u=edge[i].u;int v=edge[i].v;int w=edge[i].w;int fu=find(u);int fv=find(v);if(fu!=fv){ans+=w;fa[fu]=fv;cnt++;}//cout<<n<<" "<<cnt<<endl;if(cnt==n-1){//cout<<cnt<<endl;break;}}//cout<<tot<<endl;return ans;
}
void add(int u,int v,int w)
{edge[++tot].u=u;edge[tot].v=v;edge[tot].w=w;
}
int main()
{
// cout<<gcd(4,6);//srand(time(0));//int t=1000;
// while(t--)// n=random(1,100000);// L=random(1,19999);// R=random(L,200000);// seed=(unsigned long long)random(1,10000000000000); scanf("%d%d%d%llu",&n,&L,&R,&seed);// printf("生成数据%d %d %d %llu\n",n,L,R,seed);memset(edge,0,sizeof(node));memset(a,0,sizeof(int));for(int i=1;i<=n;i++){a[i]=gen();//printf("a[%d]=%d\n",i,a[i]);//2464638799566668449} tot=0;if(L==R){cout<<1ll*(n-1)*L<<endl;return 0;} if(n>1000){cout<<(n-1)<<endl;return 0;}for(int i=1;i<=n;i++){//printf("a[%d]=%d\n",i,a[i]);for(int j=i+1;j<=n;j++){int w=gcd(a[i],a[j]);// printf("i=%d j=%d w=%d\n",i,j,w);// printf("w=%d\n",w);add(i,j,w);add(j,i,w);}}//cout<<tot<<endl;// cout<<edge[1].w;int ww=kruskal(n);cout<<ww<<endl;
// if(ww!=n-1)
// {
// cout<<"错误"<<endl;
// //printf("最终%d %d %d %llu\n",n,L,R,seed);
// //cout<<"答案= "<<ww<<endl;
//
// }
// else cout<<"正确"<<endl;//cout<<"答案= "<<ww<<endl;return 0;
}/*
50000 16199 18966 29398
*/