题解 集合

传送门

首先最终集合大小为 \(n\) 是容易 check 的
\(n-1\) 可以先均质因数分解然后从 1 到 n 扫描线删去 \(i!\) 的质因子
这里只需要记录每个质因子的奇偶性就行

然后正解:
打表发现答案好像都和 \(n\) 差不多
尝试拆式子,先假设 \(n\) 是偶数
image
发现最坏情况是删个 2 再删个 \(\frac{n}{2}!\)
\(n\) 是奇数的话把 \(n\) 删了可以变成偶数
所以答案的下界是 \(n-3\)
于是只需要 check \(n-2\)\(n-3\) 的情况了

  • 对于「判断一个东西出现了奇数次还是偶数次」一类的问题:
    若要判断的数较少可以考虑 bitset
    若只需要知道存不存在为奇/偶的可以用异或 hash

于是 \(n-1\) 可以 check \([sum\oplus h(i!)=0]\)
\(n-2\) 可以check是否存在 \(sum\oplus h(i!)=h(j!)\)
剩下的就是 \(n-3\) 的情况了,因为达到了答案下界所以删 \(2, \frac{n}{2}, n\) 一定是合法的

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#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;

namespace force{
	ll fac[50][50], tem[50], ans, rec;
	void divide(ll n, ll* div) {
		ll m=n;
		for (ll i=2; i*i<=n; ++i) if (m%i==0) {
			do {m/=i; ++div[i];} while (m%i==0);
		}
		if (m>1) ++div[m];
	}
	void solve() {
		for (int i=1; i<=n; ++i) divide(i, fac[i]);
		//cout<<"div: "<<endl;
		//for (int i=1; i<=n; ++i) {for (int j=1; j<=n; ++j) cout<<fac[i][j]<<' '; cout<<endl;}
		for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) fac[i][j]+=fac[i-1][j];
		//cout<<"fac: "<<endl;
		//for (int i=1; i<=n; ++i) {for (int j=1; j<=n; ++j) cout<<fac[i][j]<<' '; cout<<endl;}
		int lim=1<<n;
		for (int s=1; s<lim; ++s) {
			for (int j=1; j<=n; ++j) tem[j]=0;
			for (int i=1; i<=n; ++i) if (s&(1<<(i-1))) {
				for (int j=1; j<=n; ++j) tem[j]+=fac[i][j];
			}
			for (int j=1; j<=n; ++j) if (tem[j]&1) goto jump;
			if (__builtin_popcount(s)>ans) {
				ans=__builtin_popcount(s), rec=s;
				//cout<<ans<<endl;
				//cout<<"tem: "; for (int i=1; i<=n; ++i) cout<<tem[i]<<' '; cout<<endl;
			}
			jump: ;
		}
		cout<<ans<<endl;
		for (int i=1; i<=n; ++i) if (rec&(1<<(i-1))) cout<<i<<' '; cout<<endl;
	}
}

namespace task1{
	bool tem[N], vis[N];
	set<int> s;
	vector<pair<ll, bool>> div[N];
	void divide(ll n) {
		ll m=n;
		for (ll i=2; i*i<=n; ++i) if (m%i==0) {
			pair<ll, bool> t={i, 0};
			do {m/=i; t.sec^=1;} while (m%i==0);
			div[n].pb(t);
		}
		if (m>1) div[n].pb({m, 1});
	}
	void solve() {
		for (int i=1; i<=n; ++i) {
			divide(i);
			for (auto it:div[i]) 
				if ((n-i+1)&1) {tem[it.fir]^=it.sec;}
		}
		for (int i=1; i<=n; ++i) if (tem[i]) goto jump;
		cout<<n<<endl;
		for (int i=1; i<=n; ++i) printf("%d ", i);
		cout<<endl;
		jump: ;
		//for (int i=1; i<=n; ++i) cout<<tem[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) if (tem[i]) vis[i]=1; //, cout<<i<<endl;
		for (int i=2; i<=n; ++i) {
			//cout<<"i: "<<i<<endl;
			for (auto it:div[i]) {
				tem[it.fir]^=it.sec;
				if (tem[it.fir]) vis[it.fir]=1;
				else vis[it.fir]=0;
			}
			//cout<<"s: "; for (auto it:s) cout<<it<<' '; cout<<endl;
			if (!s.size()) {
				cout<<n-1<<endl;
				for (int j=1; j<=n; ++j) if (j!=i) printf("%d ", j);
				cout<<endl;
				exit(0);
			}
		}
	}
}

namespace task{
	bool npri[N];
	int pri[N], low[N], lowp[N], lowc[N], pcnt;
	ll val[N], h[N], hf[N], sum;
	unordered_map<ll, int> mp;
	ll divide(int n) {ll ans=0; for (int t=n; t>1; t/=lowp[t]) if (lowc[t]&1) ans^=val[low[t]]; return ans;}
	void solve() {
		random_device seed;
		mt19937_64 rand(seed());
		for (int i=2; i<=n; ++i) val[i]=rand();
		for (int i=2; i<=n; ++i) {
			if (!npri[i]) pri[++pcnt]=low[i]=lowp[i]=i, lowc[i]=1;
			for (int j=1,x; j<=pcnt&&i*pri[j]<=n; ++j) {
				npri[x=i*pri[j]]=1;
				if (!(i%pri[j])) {
					low[x]=low[i];
					lowp[x]=lowp[i]*pri[j];
					lowc[x]=lowc[i]+1;
					break;
				}
				else low[x]=lowp[x]=pri[j], lowc[x]=1;
			}
		}
		for (int i=2; i<=n; ++i) h[i]=divide(i);
		for (int i=2; i<=n; ++i) mp[hf[i]=hf[i-1]^h[i]]=i;
		for (int i=2; i<=n; ++i) sum^=hf[i];
		if (!sum) {printf("%d\n", n); for (int i=1; i<=n; ++i) printf("%d ", i); printf("\n"); exit(0);}
		for (int i=2; i<=n; ++i) if (!(sum^hf[i])) {
			printf("%d\n", n-1);
			for (int j=1; j<=n; ++j) if (j!=i) printf("%d ", j); printf("\n");
			exit(0);
		}
		for (int i=2; i<=n; ++i) if (mp.find(sum^hf[i])!=mp.end()) {
			printf("%d\n", n-2);
			int t=mp[sum^hf[i]];
			for (int j=1; j<=n; ++j) if (j!=i && j!=t) printf("%d ", j); printf("\n");
			exit(0);
		}
		printf("%d\n", n-3);
		for (int i=1; i<=n; ++i) if (i!=2 && i!=n/2 && i!=n) printf("%d ", n);
		printf("\n");
	}
}

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

	n=read();
	// if (n<=20) force::solve();
	// else task1::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-02-19 15:51  Administrator-09  阅读(1)  评论(0编辑  收藏  举报