Time Limits: 7000 ms Memory Limits: 786432 KB
Description
胆小鬼连幸福都会害怕,碰到棉花都会受伤,有时还被幸福所伤。
——太宰治《人间失格》
回顾我的一生,一共有n个事件,每一个事件有一个幸福值p_i。
我想用n-1条线把所有的事件连起来,变成一个连通块。一条连接了事件x和事件y的线会产生min(p_x mod p_y,p_y mod p_x)的喜悦值。
日日重复同样的事,遵循着与昨日相同的惯例,若能避开猛烈的狂喜,自然也不会有悲痛的来袭。因此,我想知道连接起来之后产生喜悦值最小是多少。
Input
文件第一行有一个正整数n。
接下来n行,每行一个正整数p_i。
Output
输出只有一行,表示最小的喜悦值。
Sample Input
输入1:
4
2
6
3
11
输入2:
4
1
2
3
4
输出3:
3
4
9
15
Sample Output
输出1:
1
输出2:
0
输出3:
4
Data Constraint
对于30%的数据,保证1<=n<=10^3。
对于另外40%的数据,保证1<=p_i<=10^6。
对于100%的数据,保证1<=n<=10^5,1<=p_i<=10^7。
设序列中一个点值为pi,我们可以把所有大于pi*x的p中的最小的点和i连边,这样连出来的图一定包含了这个图的最小生成树
为什么呢?
不妨设(pi,pj)不满足上述条件,那么就一定有 pi∗x<pc1<pc2...<pck<pj<pi∗(x+1) 那么我们发现连(i,c1),(c1,c2)…(ck,j)这些边的值得和和直接连的值时一样的
可是我们要求的是最小生成树啊,要选确定量的边
既然效果相同,为什么不选这种能多连几条边的方法呢?
如果形成了环不就可以删去一些边使得答案更小了吗?
如此就证明了这样选边一定不会更劣只会更优
注意排序要用计数排序,快排会t
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
using namespace std;
const int maxn=1e5+5,maxp=1e7+5;
int sh[maxp],sum[maxp],rank[maxn*320],nc[maxn*320],u[maxn*320],v[maxn*320];
int cc[maxn*320],fa[maxn];
int a[maxn];
int i,j,k,l,n,m,x,y,z,now,ans,hi;
int getfather(int x){
if (fa[x]==x) return x; else fa[x]=getfather(fa[x]);
return fa[x];
}
int main(){
freopen("autosadism.in","r",stdin);
freopen("autosadism.out","w",stdout);
scanf("%d",&n);
m=0;
fo(i,1,n){
scanf("%d",&x);
if (sh[x]==0){
sh[x]=1;
a[++m]=x;
}
}
memset(sh,0,sizeof(sh));
n=m;
sort(a+1,a+n+1);
now=n;
fo1(i,a[n],1){
while (now>0 && a[now-1]>=i) now--;
sh[i]=now;
}
now=0;
fo(i,1,n-1){
j=a[i];
nc[++now]=a[sh[j+1]]%a[i]; u[now]=i; v[now]=sh[j+1];
hi=sh[j+1];
j=j+a[i];
while (j<=a[n]){
if (sh[j]==0) break;
if (hi!=sh[j]){
nc[++now]=a[sh[j]]%a[i]; u[now]=i; v[now]=sh[j];
hi=sh[j];
}
j=j+a[i];
}
}
fo(i,1,now) sum[nc[i]]++;
fo(i,1,a[n]) sum[i]+=sum[i-1];
fo(i,1,now) rank[i]=sum[nc[i]]--;
fo(i,1,now) cc[rank[i]]=i;
z=0;
fo(i,1,n) fa[i]=i;
fo(i,1,now){
x=getfather(u[cc[i]]); y=getfather(v[cc[i]]);
if (x==y) continue;
z++;
if (z>=n) break;
ans=ans+nc[cc[i]];
fa[x]=y;
}
printf("%d\n",ans);
return 0;
}