题解 分裂

传送门

首先容易看出一个第 \(i\) 次操作砸一个编号为 \(i\) 的球,最后砸一个编号为 \(n-sum\) 的球的做法
这样的复杂度是 \(O(\sqrt n)\)

然后发现每种编号的球留一个就够了,剩下的全都可以砸
于是就可以过了,复杂度应该是……阶乘的反函数?

注意当 \(n\) 很大时球数会爆 long long,要开 int128

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 20000010
#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{
// 	bool vis[N];
// 	queue<vector<int>> q;
// 	map<vector<int>, bool> mp;
// 	void solve() {
// 		q.push(vector<int>(1));
// 		int cnt=0;
// 		while (clock()<1000000000) {
// 			vector<int> u=q.front(); q.pop();
// 			// cout<<"u: "; for (auto it:u) cout<<it<<' '; cout<<endl;
// 			vis[u.size()]=1;
// 			for (int i=0; i<u.size(); ++i) {
// 				vector<int> t=u;
// 				++t[i];
// 				for (int j=2; j<=t[i]; ++j) t.pb(t[i]);
// 				sort(t.begin(), t.end());
// 				if (mp.find(t)==mp.end()) q.push(t), mp[t]=1;
// 			}
// 		}
// 		cout<<"i  : "; for (int i=1; i<=1550; ++i) cout<<setw(2)<<i<<' '; cout<<endl;
// 		cout<<"vis: "; for (int i=1; i<=1550; ++i) cout<<setw(2)<<vis[i]<<' '; cout<<endl;
// 	}
// }

namespace task1{
	int cnt[N];
	pair<int, int> sta[N];
	void solve() {
		// cout<<double(sizeof(cnt)+sizeof(sta))/1000/1000<<endl;
		if (n==3||n==5||n==8) {puts("-1"); return ;}
		int i, sum, top=0;
		cnt[1]=1;
		for (i=1,sum=1; ; ++i) {
			if (n==sum+i+1) {
				--cnt[i-1]; cnt[i]+=i;
				--cnt[2]; cnt[3]+=3;
				break;
			}
			if (n<sum+i) {
				if (n==sum) break;
				--cnt[n-sum];
				cnt[n-sum+1]+=n-sum+1;
				break;
			}
			--cnt[i]; cnt[i+1]=i+1;
			sum+=i;
		}
		for (int j=1; j<=i; ++j) if (cnt[j]) sta[++top]={j, cnt[j]};
		printf("%lld\n", top);
		for (int j=1; j<=top; ++j) printf("%lld %lld\n", sta[j].first, sta[j].second);
	}
}

namespace task2{
	void solve() {
		ll prod=1;
		for (int i=1; ; ++i) if ((prod*=i)==n) {
			cout<<1<<endl;
			cout<<i<<' '<<n<<endl;
			break;
		}
	}
}

namespace task3{
	int cnt[N];
	pair<int, int> sta[N];
	void solve() {
		// cout<<double(sizeof(cnt)+sizeof(sta))/1000/1000<<endl;
		if (n==1) {cout<<1<<endl<<1<<' '<<1<<endl; return ;}
		if (n==3||n==5||n==8) {puts("-1"); return ;}
		int i, sum, top=0;
		cnt[2]=2;
		for (i=2,sum=2; ; ++i) {
			// cout<<"i: "<<i<<endl;
			cnt[i+1]=0;
			for (int j=1,end=cnt[i]; j<end; ++j) {
				// cout<<"sum: "<<sum<<' '<<n<<' '<<cnt[i]<<endl;
				if (n==sum+i+1) {
					--cnt[i-1]; cnt[i]+=i;
					--cnt[2]; cnt[3]+=3;
					goto jump;
				}
				if (n<sum+i) {
					// cout<<"cnt: "; for (int k=1; k<=i+1; ++k) cout<<cnt[k]<<' '; cout<<endl;
					// cout<<"sum: "<<sum<<endl;
					if (n==sum) goto jump;
					--cnt[n-sum];
					cnt[n-sum+1]+=n-sum+1;
					goto jump;
				}
				--cnt[i]; cnt[i+1]+=i+1;
				sum+=i;
			}
		}
		jump: ;
		for (int j=1; j<=i+1; ++j) if (cnt[j]) sta[++top]={j, cnt[j]};
		printf("%lld\n", top);
		for (int j=1; j<=top; ++j) printf("%lld %lld\n", sta[j].first, sta[j].second);
	}
}

namespace task{
	__int128 cnt[N];
	pair<int, int> sta[N];
	void solve() {
		// cout<<double(sizeof(cnt)+sizeof(sta))/1000/1000<<endl;
		if (n==1) {cout<<1<<endl<<1<<' '<<1<<endl; return ;}
		if (n==3||n==5||n==8) {puts("-1"); return ;}
		int i, sum, top=0;
		cnt[2]=2;
		for (i=2,sum=2; ; ++i) {
			// cout<<"i: "<<i<<endl;
			// cout<<"cnt: "; for (int j=1; j<=i+1; ++j) cout<<cnt[j]<<' '; cout<<endl;
			// cout<<"sum: "<<sum<<' '<<n<<endl;
			cnt[i+1]=0;
			if (n==sum+i*cnt[i]+1) {
				// cout<<"case 1.1"<<endl;
				cnt[i+1]+=(i+1)*(cnt[i]-1);
				cnt[i]=1;
				--cnt[i-1]; cnt[i]+=i;
				--cnt[2]; cnt[3]+=3;
				break;
			}
			if (n==sum+i*(cnt[i]-1)+1) {
				// cout<<"case 1.2"<<endl;
				cnt[i+1]+=(i+1)*(cnt[i]-2);
				cnt[i]=2;
				--cnt[i-1]; cnt[i]+=i;
				--cnt[2]; cnt[3]+=3;
				break;
			}
			else if (n<=sum+i*(cnt[i]-1)) {
				int rest=(n-sum)%i;
				// cout<<"rest: "<<rest<<endl;
				if (rest==1) {
					// cout<<"case 2"<<endl;
					int tem=(n-sum)/i-1;
					assert(tem>=0);
					cnt[i]-=tem;
					cnt[i+1]+=tem*(i+1);
					--cnt[i-1]; cnt[i]+=i;
					--cnt[2]; cnt[3]+=3;
					break;
				}
				else {
					// cout<<"case 3"<<endl;
					cnt[i]-=(n-sum)/i;
					cnt[i+1]+=(n-sum)/i*(i+1);
					if (!rest) break;
					--cnt[rest];
					cnt[rest+1]+=rest+1;
					break;
				}
			}
			sum+=i*(cnt[i]-1);
			cnt[i+1]+=(i+1)*(cnt[i]-1);
			cnt[i]=1;
		}
		for (int j=i+1; j; --j) if (cnt[j]>n) {
			__int128 tem=(cnt[j]-n)/j+1;
			cnt[j]-=tem*j;
			cnt[j-1]+=tem;
		}
		for (int j=1; j<=i+1; ++j) if (cnt[j]) sta[++top]={j, cnt[j]};
		printf("%lld\n", top);
		for (int j=1; j<=top; ++j) printf("%lld %lld\n", sta[j].first, sta[j].second);
	}
}

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

	int T=read();
	while (T--) {
		n=read();
		// if (n>1e14) task2::solve();
		// else task1::solve();
		if (n<=15) task1::solve();
		else task::solve();
	}
	
	return 0;
}
posted @ 2022-03-07 18:08  Administrator-09  阅读(1)  评论(0编辑  收藏  举报