题解 小 G 的约数

传送门

  • 求在 \(n\) 的约数中选一些数使得任意两数之间不存在约数关系,问最多能选多少个数
    如果显式地建出来边的话可以发现是个 DAG
    于是就是求 DAG 上最长反链长度,可以 Dilworth 定理转为最小链覆盖然后跑网络流了
    然而有更优的解法:
    image
    一个结论:令 \(f(i)\)\(i\) 的所有质因子的指数之和,令 \(cnt_i\) 为满足 \(f(x)=i\)\(x\) 的数量
    则最长反链长度为 \(cnt_{\frac{f(n)}{2}}\)
    上面证明过程中强制 \(\operatorname{deg}(d_1)+\operatorname{deg}(d_2)=\operatorname{deg}(n)\) 是为了确保这条链经过一个 \(f(i)=\frac{f(n)}{2}\) 的点
    那现在证明了满足上述条件的最小链覆盖为 \(cnt_{\frac{f(n)}{2}}\)
    如何证明不必满足上述条件时的最小链覆盖也是 \(cnt_{\frac{f(n)}{2}}\) 呢?
    发现每个 \(f(i)=\frac{f(n)}{2}\)\(i\) 所在的链两两不同,所以 \(cnt_{\frac{f(n)}{2}}\) 已经达到可能的链覆盖下界了
    那现在背包 DP 求出 \(cnt_{\frac{f(n)}{2}}\) 就可以了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int divd[N], dcnt;

namespace force{
	int sta[N], ans=1, top;
	vector<int> rec;
	inline int gcd(int a, int b) {return !b?a:gcd(b, a%b);}
	inline int lcm(int a, int b) {return a*b/gcd(a, b);}
	void solve() {
		int lim=1<<dcnt;
		for (int s=1,cnt; s<lim; ++s) {
			top=0;
			for (int i=1; i<=dcnt; ++i) if (s&(1<<(i-1))) sta[++top]=divd[i];
			for (int i=1; i<=top; ++i)
				for (int j=i+1; j<=top; ++j) {
					// assert(n%lcm(sta[i], sta[j])==0);
					if (sta[i]*lcm(sta[i], sta[j])+sta[j]*gcd(sta[i], sta[j])<=2*sta[i]*sta[j]) goto jump;
				}
			cnt=__builtin_popcount(s);
			if (cnt>ans) ans=cnt, rec.clear(), rec.pb(s);
			else if (cnt==ans) rec.pb(s);
			jump: ;
		}
		cout<<ans<<endl;
		// for (auto it:rec) {for (int i=1; i<=dcnt; ++i) if (it&(1<<(i-1))) cout<<sta[i]<<' '; cout<<endl;}
	}
}

// namespace task1{
// 	int ans;
// 	bool vis[N];
// 	void solve() {
// 		if (dcnt<=2) {puts("1"); exit(0);}
// 		for (int i=2; i<dcnt&&!vis[i]; ++i)
// 			for (int j=i+1; j<dcnt; ++j)
// 				if (divd[j]%divd[i]==0) vis[j]=1;
// 		for (int i=2; i<dcnt; ++i) if (!vis[i]) ++ans, cout<<i<<' '; cout<<endl;
// 		cout<<ans<<endl;
// 	}
// }

namespace task3{
	int ans;
	bool vis[N];
	int solve() {
		for (int i=1; i<=dcnt&&!vis[i]; ++i)
			for (int j=i+1; j<=dcnt; ++j)
				if (divd[j]%divd[i]==0) vis[j]=1;
		for (int i=1; i<=dcnt; ++i) if (!vis[i]) ++ans;
		return ans;
	}
}

namespace task2{
	bool vis[N];
	int sta[N], tem[N], ans, top, top2;
	void solve() {
		ans=max(ans, task3::solve());
		for (int i=1; i<=dcnt; ++i) if (!task3::vis[i]) sta[++top]=divd[i];
		int cnt=0;
		while (cnt%10 || clock()<930000) {
			int t=rand()%dcnt+1;
			for (int i=1; i<=top; ++i) if (sta[i]%divd[t]==0 || divd[t]%sta[i]==0) vis[i]=1;
			top2=0;
			for (int i=1; i<=top; ++i)
				if (!vis[i]) tem[++top2]=sta[i];
				else vis[i]=0;
			for (int i=1; i<=top2; ++i) sta[i]=tem[i];
			top=top2;
			sta[++top]=divd[t];
			ans=max(ans, top);
			++cnt;
		}
		cout<<ans<<endl;
	}
}

namespace task{
	pair<int, int> div[N];
	int f[1010][1010], dcnt;
	void solve() {
		int m=n, sum=0;
		for (int i=2; i*i<n; ++i) if (m%i==0) {
			div[++dcnt]={i, 0};
			do {m/=i; ++div[dcnt].sec; ++sum;} while (m%i==0);
		}
		if (m>1) div[++dcnt]={m, 1}, ++sum;
		f[0][0]=1;
		for (int i=1; i<=dcnt; ++i)
			for (int j=0; j<=div[i].sec; ++j)
				for (int k=j; k<=sum/2; ++k)
					f[i][k]+=f[i-1][k-j];
		cout<<f[dcnt][sum/2]<<endl;
	}
}

signed main()
{
	freopen("divisor.in", "r", stdin);
	freopen("divisor.out", "w", stdout);

	n=read();
	// for (int i=1; i*i<=n; ++i) if (n%i==0) {
	// 	divd[++dcnt]=i;
	// 	if (i*i!=n) divd[++dcnt]=n/i;
	// }
	// sort(divd+1, divd+dcnt+1);
	// // cout<<"div: "; for (int i=1; i<=dcnt; ++i) cout<<divd[i]<<' '; cout<<endl;
	// if (dcnt<=2) {puts("1"); exit(0);}
	// --dcnt; swap(divd[1], divd[dcnt]); --dcnt;
	// sort(divd+1, divd+dcnt+1);
	// // if (dcnt<=22) force::solve();
	// // else task2::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-03-05 17:45  Administrator-09  阅读(1)  评论(0编辑  收藏  举报