西安郵電大學第五屆ACM-ICPC校賽 H中位因數(線性篩+dfs或者埃氏篩)

way1

這題數據10610^6,暴力枚舉ii,然後求ii的中位因子,複雜度肯定不行,我們考慮到 這樣一個性質,10610^6以內的數的做多因子個數240左右(打表可知),但大多數都是幾十個或者更少,所以對於每個數我們可以把它因子直接給求出來,然後找中位數,對於找他的因子,不能盲目根號n去找,可以先把每個數的最小素因子和最小素因子個數找出來,然後用dfs去找,這樣找出來的都是有效的,且時間也不會太多。可以均攤爲每個數幾十左右,然後對於查找到的直接找到num/2+1那個數,可以用nth_element這個函數求得,

way2

fac[i]fac[i]表示i離根號i最近的小的那個因子。
因爲最近的2個因子一定是在根號n附近,然後埃氏篩又是篩i的倍數
只要枚舉的jj大於等於i的平方,就更新fac[j]=ifac[j] = i
因爲i始終是jj的因子,只要ii<=ji*i<=j,那麼i就更新,
因爲ii一直在變大,後面大的ii覆蓋前面的,直到ii>ji*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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章