TopCoder SRM 683 Div1 500 GCDLCM2

本文探讨了质因数分解在数学运算中的应用,特别是在求最大公约数(GCD)和最小公倍数(LCM)的过程中。通过将数字分解为其质因数的幂次,可以更有效地计算GCD和LCM,并揭示了操作后质因数指数的变化规律。文章还提供了一个C++实现示例,展示了如何通过排序质因数的指数来最大化一组数的和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

神奇的结论题

首先,由于gcd(x,y)∗lcm(x,y)=x∗ygcd(x,y)*lcm(x,y)=x*ygcd(x,y)lcm(x,y)=xy,然后有个结论小学就该知道了吧,乘积一定时,两个数差得越远和越大,所以,我们应该尽量多做这种操作。

考虑将x,yx,yx,y质因数分解,设x=p1a1⋅p2a2⋯pnanx=p_1^{a_1} \cdot p_2^{a_2} \cdots p_n^{a_n}x=p1a1p2a2pnany=p1b1⋅p2b2⋯pnbny=p_1^{b_1} \cdot p_2^{b_2} \cdots p_n^{b_n}y=p1b1p2b2pnbn(若某个质因子不存在就让它的指数为零)。考虑gcd和lcm的本质,则gcd(x,y)=p1min(a1,b1)⋅p2min(a2,b2)⋯pnmin(an,bn)gcd(x,y)=p_1^{min(a_1,b_1)} \cdot p_2^{min(a_2,b_2)} \cdots p_n^{min(a_n,b_n)}gcd(x,y)=p1min(a1,b1)p2min(a2,b2)pnmin(an,bn)lcm(x,y)=p1max(a1,b1)⋅p2max(a2,b2)⋯pnmax(an,bn)lcm(x,y)=p_1^{max(a_1,b_1)} \cdot p_2^{max(a_2,b_2)} \cdots p_n^{max(a_n,b_n)}lcm(x,y)=p1max(a1,b1)p2max(a2,b2)pnmax(an,bn),然后就可以发现,每次操作过后,指数小的往小的方向移动,指数大的往大的方向移动。

所以最终的状态,应该是所有质因子按指数从小到大的顺序排列。把每个数暴力分解,sort一波就好了…

#include <bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(int i=x;i<=y;i++)
#define rf(i,x,y) for(int i=x;i>=y;i--)
using namespace std;
const int N=100001;
const int p=1e9+7;
int n;
ll a[N];
map<ll,vector<int>> mp;

template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; } 
template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; }

class GCDLCM2 {
public:
    int getMaximalSum( vector <int> start, vector <int> d, vector <int> cnt ) ;
};

void deco(ll &x){
	int s=0;
	for(ll i=2;i*i<=x;i++)
	 if (x%i==0){
	 	s=0;
	 	while(x%i==0) x/=i,s++;
	 	mp[i].push_back(s);
	 }
	if (x>1) mp[x].push_back(1),x=1;
}

ll power(ll a,int n){
	ll ans=1;
	for(ll sum=a;n;n>>=1,sum=sum*sum%p) if (n&1) ans=ans*sum%p;
	return ans;
}

int GCDLCM2::getMaximalSum(vector <int> start, vector <int> d, vector <int> cnt) {
    for(int i=0;i<start.size();i++)
     for(int j=0;j<cnt[i];j++)
      a[++n]=start[i]+1ll*j*d[i];
    //fr(i,1,n) cout<<a[i]<<' ';
    fr(i,1,n) deco(a[i]);
    for(map<ll,vector<int>>::iterator it=mp.begin();it!=mp.end();it++){
    	vector<int> v=it->second;
    	sort(v.rbegin(),v.rend());
    	for(int i=0;i<v.size();i++)
    	 a[n-i]=a[n-i]*power(it->first,v[i])%p;
    	//cout<<it->first<<' ';
    }
    ll S=0;
    //cout<<endl;
    fr(i,1,n) S=(S+a[i])%p;
    return S;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值