数学拆分问题--贪心与乘法逆元

题目链接
题意:给一个x数,可以将他拆成多个整数,并且这些整数互不相同,使得累积和最大,求累积和最大,最后取模1e9+7

题解:思考:如果将x拆成多个2的话会让答案值最大,然后再拆成三,再拆成4.....以此类推
要使答案最大可以从2 3 4 5 ....一直枚举下去,然后将剩余的k值对前面的进行遍历累加,当出现某个数a+k没有与之前重复时,这样会保证答案最大

先预处理出前缀积,然后将符合条件前缀积除去a,乘上a+k
除法因为出现取模情况,转为乘法逆元
乘法逆元:

ll ext_gcd(ll a,ll b,ll &x,ll &y)
{
	ll t,d;
	if(b==0) {x=1;y=0;return a;
	}
	d=ext_gcd(b,a%b,x,y);
	t=x;
	x=y;
	y=t-a/b*y;
	return d;
}
ll Invmod(ll a)
{
	ll x,y;
	if(ext_gcd(a,mod,x,y)!=1) return -1;
	return (x%mod+mod)%mod;
}

他人题解博客

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
ll sum[100005];
ll mult[100005];
const ll mod = 1e9+7;
ll ext_gcd(ll a,ll b,ll &x,ll &y)
{
	ll t,d;
	if(b==0) {x=1;y=0;return a;
	}
	d=ext_gcd(b,a%b,x,y);
	t=x;
	x=y;
	y=t-a/b*y;
	return d;
}
ll Invmod(ll a)
{
	ll x,y;
	if(ext_gcd(a,mod,x,y)!=1) return -1;
	return (x%mod+mod)%mod;
}
int main()
{
	ll x,i;
	int t;
	sum[1]=0,mult[1]=1;
	for(i=2;i<100005;i++)
	{
		sum[i]=sum[i-1]+i;
	}
	for(i=2;i<100005;i++)
	{
		mult[i]=mult[i-1]*i%mod;
	}
	scanf("%d",&t);
	while(t--)
	{
		ll k=0,st=0,i=0;
		scanf("%d",&x);
		if(x==1){printf("%d\n",x);continue;
		}
		i=upper_bound(sum+1,sum+100005,x)-sum;
	 	k=x-sum[i-1];
	  	st=i-1;
		i=2;
		while(1)
		{
			if(k+i>st)
			{		
				break;
			}
			i++;
		}
		ll ans=(mult[st]*Invmod(i)%mod)*(k+i)%mod;
		printf("%lld\n",ans);
	}
	return 0;
} 
posted @ 2017-12-13 17:23  Linese  阅读(362)  评论(0编辑  收藏  举报