题解 卿且去

传送门

首先发现若选了 \(x\),则 \(2x\) 不可选
所以猜测最优策略下选择集合为 \((\lfloor\frac{n}{2}\rfloor, n]\)
证明的话见这里
于是可以枚举每个数,考虑天可能产生的贡献
\(w(i)\) 表示 \(i\) 的质因子个数,\(\pi(i)\) 表示 \(i\) 以内质数的个数
于是一个数在所有 \(s\) 中的贡献是 \(2^{\pi(n)-w(n)}\)
所以答案为 \(2^{\pi(n)}((n-\lfloor\frac{n}{2}\rfloor)-\sum\limits_{\lfloor\frac{n}{2}\rfloor+1}^n2^{-w(i)})\)
发现这个 \(2^{-w(i)}\) 是积性函数,可以 Min_25 筛算

  • DAG 上的最大独立集叫做反链,是有可能求出来的
  • 关于 dilworth 定理:这里
    核心内容大概是这两条:
    1. 令偏序集上最长链长度为 \(r\),则最短反链长度为 \(r\)
    2. 令偏序集上最小链覆盖链数为 \(r\),则最长反链长度为 \(r\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#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 ll read() {
	ll 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;
}

ll n;
const ll mod=998244353;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

namespace force{
	ll ans;
	bool npri[N];
	int sta[N], tem[N], lst[N], now, top2, top;
	ll calc() {
		// cout<<"calc: "; for (int i=0; i<top2; ++i) cout<<tem[i]<<' '; cout<<endl;
		int lim=1<<top2, maxn=0;
		for (int s=0; s<lim; ++s) {
			now=0;
			for (int i=0; i<top2; ++i) if (s&(1<<i)) lst[++now]=tem[i];
			for (int i=1; i<=now; ++i)
				for (int j=1; j<=now; ++j)
					if (i!=j && lst[i]%lst[j]==0) goto jump;
			maxn=max(maxn, now);
			jump: ;
		}
		// cout<<"return: "<<maxn<<endl;
		return maxn;
	}
	void solve() {
		npri[0]=npri[1]=1;
		for (int i=2; i<=n; ++i) if (!npri[i]) {
			sta[top++]=i;
			for (int j=i*2; j<=n; j+=i) npri[j]=1;
		}
		// cout<<"sta: "; for (int i=0; i<top; ++i) cout<<sta[i]<<' '; cout<<endl;
		int lim=1<<top;
		for (int s=0; s<lim; ++s) {
			top2=0;
			for (int i=0; i<top; ++i) if (s&(1<<i)) {
				for (int j=sta[i]; j<=n; j+=sta[i])
					tem[top2++]=j;
			}
			sort(tem, tem+top2);
			top2=unique(tem, tem+top2)-tem;
			ans=(ans+calc())%mod;
		}
		printf("%lld\n", ans);
	}
}

namespace task1{
	#define M 50000010
	bool npri[M];
	ll inv[20], ans;
	int pri[M], w[M], pcnt;
	void solve() {
		for (int i=2; i<=n; ++i) {
			if (!npri[i]) pri[++pcnt]=i, w[i]=1;
			for (int j=1,x; j<=pcnt&&i*pri[j]<=n; ++j) {
				npri[x=i*pri[j]]=1;
				if (!(i%pri[j])) {w[x]=w[i]; break;}
				else w[x]=w[i]+1;
			}
		}
		for (int i=1; i<=10; ++i) inv[i]=qpow(qpow(2, i), mod-2);
		for (int i=n/2+1; i<=n; ++i) ans=(ans+inv[w[i]])%mod;
		ans=qpow(2, pcnt)*((n-n/2)-ans)%mod;
		printf("%lld\n", (ans%mod+mod)%mod);
	}
}

namespace task{
	ll n;
	bool npri[N];
	int pri[N], id1[N], id2[N], pcnt;
	ll inv[20], sp[N], uni[N], g[N], tot, ans, sqr;
	ll s(ll m, ll x) {
		// cout<<"s: "<<m<<' '<<x<<endl;
		if (m<=pri[x]) return 0;
		int id=m<=sqr?id1[m]:id2[n/m];
		ll ans=g[id]-sp[x];
		for (int i=x+1; i<=pcnt&&1ll*pri[i]*pri[i]<=m; ++i)
			for (ll j=pri[i]; j<=m; j*=pri[i])
				ans=(ans+inv[1]*(s(m/j, i)+(j!=pri[i])))%mod;
		return ans;
	}
	ll solve(ll now) {
		pcnt=ans=tot=0; n=now; sqr=sqrt(n);
		// memset(id1, 0, sizeof(id1));
		// memset(id2, 0, sizeof(id2));
		// memset(g, 0, sizeof(g));
		for (int i=1; i<=10; ++i) inv[i]=qpow(qpow(2, i), mod-2);
		for (int i=2; i<=sqr; ++i) {
			if (!npri[i]) pri[++pcnt]=i, sp[pcnt]=(sp[pcnt-1]+inv[1])%mod;
			for (int j=1; j<=pcnt&&i*pri[j]<=sqr; ++j) {
				npri[i*pri[j]]=1;
				if (!(i%pri[j])) break;
			}
		}
		for (ll l=1,r; l<=n; l=r+1) {
			r=n/(n/l);
			uni[++tot]=n/l;
			if (n/l<=sqr) id1[n/l]=tot;
			else id2[n/(n/l)]=tot;
			g[tot]=inv[1]*(uni[tot]-1)%mod;
		}
		for (int i=1; i<=pcnt; ++i) {
			for (ll j=1; j<=tot&&1ll*pri[i]*pri[i]<=uni[j]; ++j) {
				ll k=uni[j]/pri[i]<=sqr?id1[uni[j]/pri[i]]:id2[n/(uni[j]/pri[i])];
				g[j]=(g[j]-(g[k]-sp[i-1]))%mod;
			}
		}
		// cout<<"uni: "; for (int i=1; i<=tot; ++i) cout<<uni[i]<<' '; cout<<endl;
		// cout<<"g: "; for (int i=1; i<=tot; ++i) cout<<g[i]<<' '; cout<<endl;
		return s(n, 0);
	}
}

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

	n=read();
	// force::solve();
	// task1::solve();
	ll t1=task::solve(n), tg=(task::g[1]*2%mod+mod)%mod;
	ll t2=task::solve(n/2);
	//cout<<"tg: "<<tg<<endl;
	// cout<<"t: "<<t1<<' '<<t2<<endl;
	printf("%lld\n", ((qpow(2, tg)*((n-n/2)-(t1-t2)))%mod+mod)%mod);
	//cout<<task::solve(4)-task::solve(2)<<endl;
	
	return 0;
}
posted @ 2022-02-07 19:19  Administrator-09  阅读(0)  评论(0编辑  收藏  举报