西安邮电大学第五届ACM-ICPC校赛 H中位因数(线性筛+dfs或者埃氏筛)

way1

这题数据 1 0 6 10^6 ,暴力枚举 i i ,然后求 i i 的中位因子,复杂度肯定不行,我们考虑到 这样一个性质, 1 0 6 10^6 以内的数的做多因子个数240左右(打表可知),但大多数都是几十个或者更少,所以对于每个数我们可以把它因子直接给求出来,然后找中位数,对于找他的因子,不能盲目根号n去找,可以先把每个数的最小素因子和最小素因子个数找出来,然后用dfs去找,这样找出来的都是有效的,且时间也不会太多。可以均摊为每个数几十左右,然后对于查找到的直接找到num/2+1那个数,可以用nth_element这个函数求得,

way2

f a c [ i ] fac[i] 表示i离根号i最近的小的那个因子。
因为最近的2个因子一定是在根号n附近,然后埃氏筛又是筛i的倍数
只要枚举的 j j 大于等于i的平方,就更新 f a c [ j ] = i fac[j] = i
因为i始终是 j j 的因子,只要 i i < = j i*i<=j ,那么i就更新,
因为 i i 一直在变大,后面大的 i i 覆盖前面的,直到 i i > j i*i>j 之后结束

way1_code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 1e6+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair<int,int>
#define pal pair<ll,ll>
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;

int prime[man],vis[man];
int m_prime[man],num[man];
void init(){
    int cnt=0;
    for(int i=2;i<man;++i){
        if(!vis[i]){
            prime[++cnt]=i;
			m_prime[i] = i;
			num[i] = 1;
        }
        for(int j=1;j<=cnt&&i*prime[j] < man;++j){
            vis[prime[j]*i]= 1;
            if(i%prime[j]==0){
				m_prime[i*prime[j]] = prime[j];
				num[i*prime[j]] = num[i] + 1;
                break;
            }
			m_prime[i*prime[j]] = prime[j];
			num[i*prime[j]] = 1;
        }
    }
}
ll p[man];
int fac[man],fac_num[man],fac1[man];
int fa_num = 0;
void dfs(int a,int dep,int n){
	if(dep-1==n){
		fac1[++fa_num] = a;
		return;
	}
	for(int i = 0;i <= fac_num[dep];i++){
		if(i!=0)a *= fac[dep];
		dfs(a,dep+1,n);
	}
}

int main() {
	#ifndef ONLINE_JUDGE
		//freopen("in.txt", "r", stdin);
		//freopen("out.txt","w",stdout);
	#endif
	init();
	for(int i = 1;i < man;i++){
		int tp = i;
		int cnt = 0;
		fa_num = 0;
		fac[0] = 1;
		while(tp!=1){
			fac[++cnt] = m_prime[tp];
			fac_num[cnt] = num[tp];
			while(tp%fac[cnt]==0)tp /= fac[cnt];
		}
		dfs(1,0,cnt);
		nth_element(fac1+1,fac1+fa_num/2+1,fac1+1+fa_num);
		p[i] = (p[i-1] + (fac1[fa_num/2+1] + i / fac1[fa_num/2+1])/2)%mod;
	}
	int t;
	cin >> t;
	while(t--){
		int n;cin >> n;
		cout <<p[n] << endl;
	}
	return 0;
}

way2_code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 1e6+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair<int,int>
#define pal pair<ll,ll>
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
int fac[man];
 
void init(){
    for(int i = 1;i < man;i++){
        for(int j = i;j < man;j += i){
            if(1ll * i * i <= j)fac[j] = i;
        }
    }
}
 
int main() {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    init();
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        ll ans = 0;
        for(int i = 1;i <= n;i++){
            ans = (ans + (fac[i] + i / fac[i])/2 ) %mod;
        }
        cout <<ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43571920/article/details/106311653