题目链接
题目大意:
就是给定n,然后对于每一对x,y其中2
≤
\le
≤|x|,|y|
≤
n
\le n
≤n,且x是y的倍数(或者y是x的倍数),倍数至少为2。然后当前值会从x变成y,然后一直变换下去,但是如果x->y出现过了,则x->y和y->x都不能再出现了,则每一次变换得分就是他们的倍数。求一个变换序列中积分最多是多少?
解题思路:
看样例:2 -> 4 -> -2 -> -4 ->2可以发现从2开始然后跟他的倍数4,-4和自己的+2,-2进行变换之后,会重新变换成2,且中间经历了4次,就可以知道对于任何一对有倍数关系的x,y积分都可以+4*倍数,但是相加之间必须是有关系的,比如:2 - 6 - 3,5就分为两组,即他们之间必须通过倍数能连接在一起,此时的积分才能累加。比如n = 6 ,则 (2)->(6)->(3)->(-6)->(-3)->(6)->(-2)->(-6)->(2),可以发现2到6然后6去处理了一下它的因子3然后状态返回6,则6跟2之间的状态不变,所以直接处理倍数然后加起来就行了。
首先把能联系起来的数都放在一起,用并查集就可以了,然后再按集合算一下积分取最大值可以了。
实验代码:
#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=1e5+10;
int pre[maxn];
ll sum[maxn];
int f(int x)
{
return pre[x] = (pre[x]==x? x:f(pre[x]));
}
void in(int x,int y)
{
x=f(x);
y=f(y);
pre[x]=y;
}
int main()
{
int n;
cin>>n;
for (int i=1;i<=n;i++)
pre[i]=i;
for (int i=2;i<=n;i++)
{
for (int j=2;j*i<=n;j++)
{
in(i,j);
}
}
for (int i=2;i<=n;i++)
{
int fa=f(i);
for (int j=2;j*i<=n;j++)
{
sum[fa]+=j*4ll;
}
}
ll ans=0;
for (int i=1;i<=n;i++)
{
ans=max(ans,sum[i]);
}
cout<<ans;
return 0;
}