2016 Multi-University Training Contest 1
题意:n个数 m条边 求最小生成树,和最小生成树上任意两点之间的平均距离
思路:最小生成树上任意两点之间的平均距离=总的距离/点的对数
总的距离=所有路径中每条边出现的次数*权值
所有路径每条边出现的次数=该点为根树的节点数*(n-该点为根树的节点数)
点的对数为=n*(n-1)/2;
prim邻接表:O(elogv)
K邻接表:O(eloge)
1 // #pragma comment(linker, "/STACK:102c000000,102c000000") 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <sstream> 6 #include <string> 7 #include <algorithm> 8 #include <list> 9 #include <map> 10 #include <vector> 11 #include <queue> 12 #include <stack> 13 #include <cmath> 14 #include <cstdlib> 15 // #include <conio.h> 16 using namespace std; 17 #define clc(a,b) memset(a,b,sizeof(a)) 18 #define inf 0x3f3f3f3f 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 const int N = 1e5+10; 22 const int M = 1e6+10; 23 const int MOD = 1e9+7; 24 #define LL long long 25 #define mi() (l+r)>>1 26 double const pi = acos(-1); 27 28 void fre() { 29 freopen("in.txt","r",stdin); 30 } 31 32 // inline int r() { 33 // int x=0,f=1;char ch=getchar(); 34 // while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();} 35 // while(ch>='0'&&ch<='9') { x=x*10+ch-'0';ch=getchar();}return x*f; 36 // } 37 38 struct Edge{ 39 int u,v,w; 40 int next; 41 Edge(int u_=0,int v_=0,int w_=0):u(u_),v(v_),w(w_){} 42 bool operator < (const Edge &rhs) const{ 43 return w>rhs.w; 44 } 45 }e2[N*2],e1[M*2]; 46 47 int tot,n,m; 48 int h1[N],h2[N]; 49 double dp[N]; 50 int sum[N]; 51 52 void init(){ 53 clc(h1,-1); 54 tot=0; 55 clc(dp,0); 56 } 57 58 void add1(int u,int v,int w){ 59 e1[tot].v=v; 60 e1[tot].w=w; 61 e1[tot].next=h1[u]; 62 h1[u]=tot++; 63 } 64 void add2(int u,int v,int w){ 65 e2[tot].u=u; 66 e2[tot].v=v; 67 e2[tot].w=w; 68 e2[tot].next=h2[u]; 69 h2[u]=tot++; 70 } 71 int d[N]; 72 bool vis[N]; 73 priority_queue<Edge>q; 74 LL prim(){ 75 LL ans; 76 ans=0; 77 while(!q.empty())q.pop(); 78 q.push(Edge(-1,1,0)); 79 clc(vis,0); 80 for(int i=1;i<=n;++i) d[i]=inf,h2[i]=-1,vis[i]=0; 81 tot=0; 82 d[1]=0; 83 int cnt=0; 84 while(!q.empty()){ 85 Edge tmp=q.top(); 86 q.pop(); 87 if(vis[tmp.v])continue; 88 if(tmp.u!=-1){ 89 add2(tmp.u,tmp.v,tmp.w); 90 add2(tmp.v,tmp.u,tmp.w); 91 } 92 ans+=tmp.w; 93 vis[tmp.v]=true; 94 ++cnt; 95 if(cnt==n)break; 96 for(int i=h1[tmp.v];~i;i=e1[i].next){ 97 int v=e1[i].v; 98 if(vis[v])continue; 99 int w=e1[i].w; 100 if(d[v]>w){ 101 d[v]=w; 102 q.push(Edge(tmp.v,v,d[v])); 103 } 104 } 105 } 106 return ans; 107 } 108 109 110 void dfs(int u,int f){ 111 sum[u]=1; 112 for(int i=h2[u];~i;i=e2[i].next){ 113 int v=e2[i].v; 114 if(v==f) continue; 115 dfs(v,u); 116 sum[u]+=sum[v]; 117 dp[u]+=dp[v]+1.0*e2[i].w*sum[v]*(n-sum[v]); 118 } 119 } 120 int main(){ 121 // fre(); 122 int T; 123 scanf("%d",&T); 124 while(T--){ 125 scanf("%d%d",&n,&m); 126 init(); 127 for(int i=0;i<m;i++){ 128 int u,v,w; 129 scanf("%d%d%d",&u,&v,&w); 130 add1(u,v,w); 131 add1(v,u,w); 132 } 133 LL ans=prim(); 134 dfs(1,-1); 135 double q=(double)n*(n-1)/2; 136 printf("%I64d %.2f\n",ans,dp[1]/q); 137 } 138 return 0; 139 }
题意:n个数,q次询问,输出数组中有多少对区间的gcd = l到r的gcd
思路:官方题解
我们注意观察gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar),当l固定不动的时候,r=l...nr=l...n时,我们可以容易的发现,随着rr的増大,gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar)是递减的,同时gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar)最多 有log\ 1000,000,000log 1000,000,000个不同的值,为什么呢?因为a_{l}al最多也就有log\ 1000,000,000log 1000,000,