题意:
就是给你一个数组全排列,任意两点间的距离是abs(i-j)*abs(p[i]-p[j])。现在问你所有点联通起来的最小花费。n<=40000。
思考:
代码:
#include
#define fi first
#define se second
#define pb push_back
#define db double
#define PII pair<int,int >
#define mem(a,b) memset(a,b,sizeof(a))
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod = 1e9+7,inf = 1e9;
const int N = 5e4+10,M = 5e7+5;
struct node{
int a,b,ne;
}e[M];
int T,n,m,k;
int va[N];
int pos[N];
int acc[N];
int h[N],idx;
int add(int a,int b,int c)
{
e[idx].a = a;
e[idx].b = b;
e[idx].ne = h[c];
h[c] = idx++;
}
int find(int x)
{
if(acc[x]!=x) acc[x] = find(acc[x]);
return acc[x];
}
int krukal()
{
int ans = 0,sum = 0;
for(int i=0;i<=n-1;i++)
{
for(int j=h[i];j!=-1;j=e[j].ne)
{
int t1 = find(e[j].a),t2 = find(e[j].b);
if(t1!=t2)
{
acc[t1] = t2;
ans += i;
if(++sum>=n-1) break;
}
}
if(sum>=n-1) break;
}
return ans;
}
void init()
{
idx = 0;
for(int i=0;i<=n;i++)
{
h[i] = -1;
acc[i] = i;
}
}
signed main()
{
IOS;
cin>>T;
while(T--)
{
cin>>n;
init();
for(int i=1;i<=n;i++)
{
cin>>va[i];
pos[va[i]] = i;
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;(i-j)*(i-j)<n&&j<=n;j++)
{
int c = abs(i-j)*abs(va[i]-va[j]);
if(c<n) add(i,j,c);
}
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;(i-j)*(i-j)<n&&j<=n;j++)
{
int c = abs(i-j)*abs(pos[i]-pos[j]);
if(c<n) add(pos[i],pos[j],c);
}
}
cout<<krukal()<<"\n";
}
return 0;
}
总结:
多多思考,理解本质。