UVA 数学题选做

UVA12716 GCD等于XOR GCD XOR

考虑枚举 (c=gcd(a,b)),因为 (gcd(a,b)|aland gcd(a,b)|b),所以再枚举 (a),且 (a)(c) 的倍数。因为 (gcd(a,b)=a operatorname{xor} b),所以 (b=coperatorname{xor} a),然后再验证 (gcd(a,b)) 是否等于 (c) 即可。

但实际上我们可以知道 (gcd(a,b)) 一定等于 (a-b)。不妨令 (a>b)(因为 (a=b) 的情况一定不合法),因为 (a-ble a operatorname{xor} b le a+b)(gcd(a,b)=gcd(b,a-b)le a-b),结合两个式子就可以得到 (gcd(a,b)=a-b)

于是枚举 (c,a),算出 (b=a-c) 并验证 (aoperatorname{xor} b) 是否等于 (a-b) 即可。

因为数据组数比较多,所以考虑算出某个特定的 (a) 的答案,并进行一次前缀和,时间复杂度为 (O(nlog n+T))

UVA11440 帮帮 Tomisu Help Tomisu

一个数 (x) 的所有大于 (1) 的因子都大于 (Miff x perp M!)

因为 (Nge M) 所以 (M!|N!),同时我们知道 (xperp M!iff (xmod M!) perp M!),于是答案就是 (varphi(M!)frac{N!}{M!})

考虑怎么求 (varphi(M!)):我们知道 (varphi(x)=x(1-dfrac{1}{p_1})(1-dfrac{1}{p_2})dots(1-dfrac{1}{p_k})),当 (M) 是质数的时候,它会贡献 ((M-1)),即 (varphi(M!)=varphi((M-1)!) imes (M-1));当 (M) 不是质数的时候,它会贡献 (M)。递推即可。

UVA1642 魔法GCD Magical GCD

考虑枚举这个区间的右端点,并维护所有最优的左端点。

可以发现,(gcd(a_ldots a_r)|gcd(a_{l+1}dots a_r)),于是在固定右端点的情况下,(gcd) 值不同的位置只有 (log n) 个。暴力维护每个 (gcd) 值对应的最靠右的左端点,将右端点向右移动的过程中进行修改即可。时间复杂度 (O(n log^2 n))

顺便讲讲我的屑做法:用 sparse table 记录区间 (gcd),枚举右端点以及 (gcd) 并二分。但这复杂度巨高,大概是 (O(sum d(a_i)log ^2n)) 的。

代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <map>
#include <algorithm>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
template<typename T> void Read(T &x){
	x=0;int _f=1;
	char ch=getchar();
	while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
	x=x*_f;
}
template<typename T,typename... Args> void Read(T &x,Args& ...others){
	Read(x);Read(others...);
}
typedef long long ll;
const int N=1e5+5;
int T,n;ll a[N];
int main(){
	Read(T);
	while(T--){
		Read(n);For(i,1,n) Read(a[i]);
		map<ll,int> mp;ll ans=0;
		For(i,1,n){
			map<ll,int> temp;
			for(const auto &x_:mp){
				pair<ll,int> x{__gcd(x_.first,a[i]),x_.second};
				if(!temp.count(x.first)) temp.insert({x.first,x.second});
				else temp[x.first]=min(temp[x.first],x.second);
			}
			if(!temp.count(a[i])) temp.insert({a[i],i});
			mp=temp;
			for(const auto &x:mp){
				ans=max(ans,x.first*(i-x.second+1));
			}
		}
		printf("%lld
",ans);
	}
	return 0;
}
Written by Alan_Zhao
原文地址:https://www.cnblogs.com/alan-zhao-2007/p/uva-math-bugaboos.html