这道题真感觉没什么思路。。
通过看杨辉三角,一开始写了个暴搜,虽然有很多剪枝,也优化了很多,但还是果断TLE。。
附上TLE的代码:(心情复杂.jpg)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
using namespace std;
#define ll long long
typedef pair<ll,ll>pp;
const double pi=acos(-1.0);
const double eps=1e-9;
const int INF=0x3f3f3f3f;
const ll MOD=1e9+7ll;
ll m;
ll fac(ll m,ll n)
{
ll ans=1;
for(ll i=1;i<=m;i++)
{
ans*=n-i+1;
ans/=i;
}
return ans;
}
pp p[1234567];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cin>>m;
if(m==2)
{
printf("1\n");
printf("(2,1)\n");
}
else
{
ll ans=0;
ll tol=0;
memset(p,0,sizeof(p));
vector<int>v[2];
v[0].clear();v[1].clear();
v[0].push_back(1);v[0].push_back(2);v[0].push_back(1);
for(ll i=3;i<m;i++)
{
ll k=i/2;
v[1].push_back(1);
for(ll j=1;j<v[0].size();j++)
v[1].push_back(v[0][j-1]+v[0][j]);
v[1].push_back(1);
/*for(ll j=0;j<v[1].size();j++)
cout<<v[1][j]<<" ";
cout<<endl;*/
v[0].clear();
for(ll j=0;j<v[1].size();j++)
v[0].push_back(v[1][j]);
if(v[1][k]<m)
{
v[1].clear();
continue;
}
for(ll j=1;j<=k;j++)
{
if(v[1][j]==m)
{
p[++tol].first=i,p[tol].second=j;
p[++tol].first=i,p[tol].second=i-j;
break;
}
if(v[1][j]>m)
break;
}
v[1].clear();
}
printf("%lld\n",tol+(ll)2);
for(int i=1;i<=tol;i++)
printf("(%lld,%lld) ",p[i].first,p[i].second);
printf("(%lld,%lld) ",m,(ll)1);
printf("(%lld,%lld) \n",m,m-1);
}
}
return 0;
}
之后听某大佬说,C(60,30)就已经到10^15次了Orz,所以k最大就是30,后来发现27就可以。
附上参考博客Orz:https://blog.csdn.net/u014800748/article/details/45424285
因为m非常大,枚举n就会十分困难,所以不如枚举k,二分n。
对于k来说,下界为2*k,上界为m。(n越大,C(n,k)就越大。实在想不通就举个例子试一下)
然后发现一个神奇的地方:求阶乘的函数fac里的那个循环,if判断不能少,不然会WA。。
我觉得这个很迷啊。。fac函数的原理主要是:C(n,k)=(n-k+1)/k*C(n,k-1),可以中间直接进行判断返回,即如果发现算到第i步时结果已经超过m了,说明n肯定不是解,返回一个m+1。按理说不加也可以,而且我试着变成判断if((ans/i*(n-i+1))>m),结果也WA了,很可能是爆了long long。。
附上AC代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define ll long long
typedef pair<ll,ll>pp;
const ll MOD=1e9+7ll;
ll m;
set<pp>ans;
ll fac(int k,ll n)
{
ll ans=1;
for(int i=1;i<=k;i++)
{
//如果发现算到第i步时结果已经超过m了,说明n肯定不是解,返回一个m+1
if((ans/i)>(m/(n-i+1)))
return m+1;
ans*=(n-i+1);
ans/=i;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cin>>m;
if(m==2)
{
printf("1\n");
printf("(2,1)\n");
}
else
{
ans.clear();
/*ans.insert(make_pair(m,1));
ans.insert(make_pair(m,m-1));*/
for(ll k=1;k<=27;k++)
{
ll l=2*k;
ll r=m;
while(l<=r)
{
ll mid=(l+r)/(ll)2;
ll tmp=fac(k,mid);
if(tmp==m)
{
ans.insert(make_pair(mid,k));
if(mid==2*k)//注意!!
break;
ans.insert(make_pair(mid,mid-k));
break;
}
else if(tmp<m)
l=mid+1;
else
r=mid-1;
}
}
ll len=ans.size();
cout<<len<<endl;
if(len==0)
continue;
pp p;
for(int i=0;i<len;i++)
{
p=(*ans.begin());
cout<<"("<<p.first<<","<<p.second<<") ";
ans.erase(ans.begin());
}
printf("\n");
}
}
return 0;
}
我我我...我好菜啊啊啊啊55555...