题解 分裂
首先容易看出一个第 \(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;
}