n=1时,显然答案与顺序无关。现在假设size<n的树的答案与顺序都无关,我们来证明size=n的树的答案与顺序无关。
若根的儿子只有一个,那么得证。现假设根的儿子至少有两个。
我们用ANS(x)表示只有根和根的儿子x以及x的子树的子问题的答案,即从根出发,巡游完x的子树并回到根的答案。
我们用SZ(x)表示以x为根的子树的大小的两倍(即从根开始巡游x这个子树再回到根的天数)。
我们假定我们访问根的儿子的顺序是s1,s2…sm,那么总的答案就为ANS(s1)+SZ(s1)(SZ(s2)+SZ(s3)…+SZ(sm))+ANS(s2)+SZ(s2)(SZ(s3)+SZ(s4)+…SZ(sm))+…+ANS(sm)。
注意到总的答案为所有儿子的ANS的和再加上两两儿子之间SZ的积的和。由于儿子至少有两个,所以儿子的子树大小一定小于n,通过归纳法得知它们的ANS与顺序无关。两两儿子之间SZ的积的和也与顺序无关。所以size=n的树的总答案与顺序无关。
#include<bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<n;i++)
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
typedef long long ll;
typedef pair<int, int>P;
#define X first
#define Y second
const int MAXN=1<<19,MAXM=1e7+5;
vector <P> V[MAXM];
int najbliz[MAXM];
int p[MAXN];
int n;
int root[MAXN],rnk[MAXN];
int bio[MAXM],ozn[MAXM];
int find(int x)
{
if(root[x]==-1)
return x;
return root[x]=find(root[x]);
}
void merge(int a,int b)
{
a=find(a);
b=find(b);
assert(a!=b);
if(rnk[a]>rnk[b])
root[b]=a;
else if(rnk[b]>rnk[a])
root[a]=b;
else
{
rnk[a]++;
root[b]=a;
}
}
int main()
{
scanf("%d",&n);
memset(ozn,-1,sizeof ozn);
REP(i,n)
{
scanf("%d",&p[i]);
najbliz[p[i]]=p[i];
if(ozn[p[i]]==-1)
ozn[p[i]]=i;
}
for(int i=MAXM-2;i>=0;i--)
if(!najbliz[i])
najbliz[i]=najbliz[i+1];
REP(i,n)
{
if(bio[p[i]]++)
continue;
if(najbliz[p[i]+1])
{
if(2*p[i]>=MAXM||najbliz[2*p[i]]!=najbliz[p[i]+1])
V[najbliz[p[i]+1]-p[i]].push_back(P(i,ozn[najbliz[p[i]+1]]));
}
for(int j=2*p[i];j<MAXM&&najbliz[j];j+=p[i])
if(j+p[i]>=MAXM||najbliz[j+p[i]]!=najbliz[j])
V[najbliz[j]-j].push_back(P(i,ozn[najbliz[j]]));
}
memset(root,-1,sizeof root);
ll rje=0;
REP(i,MAXM)
REP(j,(int)
V[i].size())
if(find(V[i][j].X)!=find(V[i][j].Y))
{
merge(V[i][j].X,V[i][j].Y);
rje+=i;
}
REP(i,n)
if(ozn[p[i]]==i)
{
assert(find(i)==find(0));
}
printf("%lld\n",rje);
return 0;
}