51nod 1040 传送门:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1040
求1-n与n的gcd之和,n<=1e9
一个一个求肯定是不行的,所以需要一些方法咯
首先,如果x与n的gcd为gcd(x,n),所以gcd(x/gcd(x,n),n/gcd(x,n))=1,所以我们可以搜索n的因子nn,然后求nn的欧拉函数(与nngcd为1的数字个数为tmp),然后tmp*n/nn就是gcd为n/nn的数字的gcd之和。
先求出n的欧拉函数phi,然后对于一个素因子k,如果k只有一个,n/k的欧拉函数为phi/(k-1),否则n/k的欧拉函数为phi/k
通过搜索n的每一个因子,答案为sigma(phi[d]*n/d)(d|n)
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 1000005 #define MAXN 1000005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ bool prime[100005]; int pr[100005]; int tot; vector<int> v; set<int> s; LL ans; int n; void init(){ mem(prime,0);tot=0; for(int i=2;i<100000;i++){ if(!prime[i]){ for(int j=2*i;j<100000;j+=i) prime[j]=1; pr[tot++]=i; } } } void dfs(int x,int ph,int j){ if(s.count(x)) return ; else{ s.insert(x); ans+=(LL)ph*(n/x); } for(int i=j;i<v.size();i++){ int tmp=ph; int k=x; while(k%v[i]==0){ k/=v[i]; if(k%v[i]==0) tmp/=v[i]; else tmp/=(v[i]-1); dfs(k,tmp,j+1); } } } int main(){ //freopen("in.txt","r",stdin); cin>>n; init(); v.clear(); int k=n; for(int i=0;i<tot&&pr[i]*pr[i]<=k;i++){ if(k%pr[i]==0){ while(k%pr[i]==0) k/=pr[i]; v.push_back(pr[i]); } } if(k!=1) v.push_back(k); int phi=n; for(int i=0;i<v.size();i++){ phi=phi/v[i]*(v[i]-1); } ans=0; dfs(n,phi,0); cout<<ans<<endl; return 0; }
51nod 1060 传送门:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1060
求1-n里面因子数量最多的,并且最小的数n<=1e18
由于1e18分解质因数,也就最多60多个数相乘,所以可以直接爆搜解决问题
因为a=p1^k1 * p2^k2 * p3^k3 *...* pn^kn
它的因子数量为(k1+1)*(k2+1)*(k3+1)*...*(kn+1)
所以搜索时记录当前值的大小,和这会应该搜索的素因子pi,以及当前因子个数,每次搜索往下都是搜索后一种素因子,不在同一个素因子上递归
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 1000005 #define MAXN 1000005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ LL n; LL ans; int maxn; bool prime[10005]; int pr[10005]; int tot; void init(){ mem(prime,0);tot=0; for(int i=2;i<10000;i++){ if(!prime[i]){ for(int j=i*i;j<10000;j+=i) prime[j]=1; pr[tot++]=i; } } } void dfs(int f,int num,int nu,LL tmp){ LL ret=tmp; if(tmp<=n){ if(nu>maxn){ maxn=nu; ans=tmp; } else if(nu==maxn) ans=min(ans,tmp); } for(int i=1;i<=num;i++){ if(ret>n/pr[f]) break;//防止爆LL ret*=pr[f]; dfs(f+1,i,nu*(i+1),ret); } } int main(){ //freopen("in.txt","r",stdin); int t; cin>>t; init(); while(t--){ cin>>n; maxn=0; ans=0; dfs(0,100,1,1); cout<<ans<<" "<<maxn<<endl; } return 0; }