题面
首先问题转化为选取一个
(Mi,Vi)
的集合,该集合必须满足若
Mk|lcm{Mi}
,
(Mk,Vk)
必须在集合中,最大化
∑Vi
。
先考虑所有
M
都两两互质的情况,对于每个元素我们都可以贪心选或不选。
然后我们想到暴力枚举
考虑把质因子分大于还是小于
maxM−−−−−−√
来考虑,利用每个数只有一个大于
maxM−−−−−−√
的质因子,把每个
Mi
分成
M′i
和
Pi
,
Pi
为大于
maxM−−−−−−√
的质因子,没有则为1,
M′i
则为剩下的部分。
于是我们只需要枚举
lcm{M′i}
,对于一个
M′k|lcm{M′i}
,若
Pk=1
,则必选,否则按
Pk
分类,若一类的贡献
>0
则贪心选即可。复杂度是可以接受的。
因为
28∗35∗53∗73∗112∗132∗172∗192
还没爆longlong,所以及其好写。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int R=7;
int n,pri[8]={2,3,5,7,11,13,17,19},ans;
struct node
{
int r,p,w;
bool operator <(node b){return p<b.p;}
}a[510];
void find(int v,ll tot)
{
if(v>R)
{
int cal=0,cnt=0;
for(int i=1;i<=n;i++)
{
if(tot%a[i].r==0) cnt+=a[i].w;
if(a[i].p!=a[i+1].p)
{
if(a[i].p!=1) cnt=max(cnt,0);
cal+=cnt;cnt=0;
}
}
ans=max(ans,cal);
return ;
}
for(int t=1;t<=500;t=t*pri[v])
find(v+1,tot*t);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].p,&a[i].w);a[i].r=1;
for(int j=0;j<=R;j++)
while(a[i].p%pri[j]==0) a[i].p/=pri[j],a[i].r*=pri[j];
}
sort(a+1,a+n+1);
find(0,1);
printf("%d",ans);
return 0;
}