题意:T组样例,每组给定一个长度为n的线段,要求把线段拆分为不同的线段n=x1+x2+..+xn,使得x1*x2*x3*..*xn最大
思路:根据均值不等式可以知道x1=x2=..=xn可以使得结果最大,但是线段之间不能相等,所以最终的到的结果线段之间一定是趋近于相等的,但是不知道最终是怎么取值,于是打表找规律
打表代码
int q[N];
int ma;
vector<int>v;
void dfs(int u,int idx,int sum)
{
if(sum>n)return;
if(sum==n)
{
int now=1;
_for(i,idx)now*=q[i];
if(now>ma)
{
ma=now;
v.clear();
_for(i,idx)v.pb(q[i]);
}
}
for(int i=u+1;i<=n;i++)
{
q[idx]=i;
dfs(i,idx+1,sum+i);
}
}
void solve()
{
while(cin>>n)
{
ma=0;
dfs(0,0,0);
cout<<"线段";for(auto i:v)cout<<i<<" ";cout<<endl;
}
return ;
}
可以发现线段个数为3,4,5的第一个分别是2,3,4;2,3,4,5;2,3,4,5,6的等差数列,而线段个数为3,4,5的第二,三,四个分别是前一个的最后一项+1,倒数第二项+1,倒数第三项+1,到第一项+1之后再循环往复,于是可以二分找到线段的个数,然后得到当前线段长度和线段个数为x个的第一个数列的差d,然后x/d就是按照前后项+1的规律每一项增加了多少组,x%d就是最后后面x%d个还额外加了1。
由于这道题目遍历整个数列也会超时,于是先预处理前100000个数的阶乘和阶乘逆元,然后每次查询就可以在O(log(n))的时间复杂度计算出线段个数,然后O(1)计算出最大答案
最终代码:
#include <map>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e6+10,INF=4e18,P=1e9+7;
int n,m;
int res[N];
bool check(int x)
{
return (2+x)*(x-1)/2<=n;
}
int qmi(int a,int b,int P)
{
int res=1;
while(b)
{
if(b&1)res=res*a%P;
a=a*a%P;
b>>=1;
}
return res;
}
int A[N],FA[N];
void init()
{
A[1]=1;
FA[1]=qmi(1ll,P-2,P);
for(int i=2;i<50000;i++)
{
A[i]=A[i-1]*i%P;
FA[i]=qmi(A[i],P-2,P);
}
return;
}
void solve()
{
sf(n);
if(n==1)
{
puts("1");
return;
}
int l=2,r=1e5;
while(l+1<r)
{
int mid=l+r>>1;
check(mid)?l=mid:r=mid;
}
int len=l-1;
int now=(2+l)*(l-1)/2;
int cha=(n-now)/len;
int yu=(n-now)%len;
int ans=A[len-yu+1+cha]*FA[cha+1]%P*A[len+2+cha]%P*FA[len-yu+2+cha]%P;
printf("%lld\n",ans);
return ;
}
signed main()
{
init();
int T=1;
sf(T);
while(T--)
solve();
return 0;
}