HDU-5976
首先要想到贪心策略,下面是我想到贪心策略后没有优化的傻逼写法,直接T掉了
#include<set>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
int t;
const ll mod=1000000007;
int main()
{
ll k;
scanf("%d",&t);
while(t--)
{
scanf("%lld",&k);
if(k<=4)printf("%lld\n",k);
else
{
ll n;
n=(sqrt(8*k+9)-1)/2;
ll sum;
sum=(2+n)*(n-1)/2;//2+3+..+n
ll m,w;
w=(k-sum)/(n-1);
m=(k-sum)%(n-1);
ll ans=1;
if(w)
{
for(ll j=n;j>=2;j--)
{
if(m)
{
ans*=(j+1+w);
m--;
}
else
ans*=(j+w);
ans%=mod;
}
}
else
{
for(ll j=n;j>=2;j--)
{
if(m)
{
ans*=(j+1);
m--;
}
else
ans*=j;
ans%=mod;
}
}
printf("%lld\n",ans);
}
}
return 0;
}
- `下面是化简,求逆元后 的的优化写法``代码中有详细的备注
```cpp
#include<set>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
int t;
const ll mod=1000000007;
const int maxn=100001;
//
ll N[maxn];//求阶乘的摸
//ll inv[maxn];
ll inv(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
{
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
N[0]=N[1]=1;
for(int i=2; i<maxn; i++)
N[i]=i*N[i-1]%mod;
ll k;
scanf("%d",&t);
while(t--)
{
scanf("%lld",&k);
if(k<=4)printf("%lld\n",k);
else
{
ll n;
n=(sqrt(8*k+9)-1)/2;//算出来的n表示2+3+..+n<=k 且2+3+...+n+(n+1)>k 表达式是自己解方程解出来的 n最大44720
ll sum;
sum=(2+n)*(n-1)/2;//2+3+..+n
ll m,w;
w=(k-sum)/(n-1);//2 -- n 每个数加 w
m=(k-sum)%(n-1);//(n-m+1) -- n 每个数加 1
/** 相当于求(2+w)*(3+w)*...*(n-m+w)*(n-m+w+1+1)*...*(n+w+1)
即 (n+w+1)! / (1+w)! / (n-m+w+1)
即 (n+w+1)! * inv {(1+w)!} * inv(n-m+w+1)
*/
int ans=1;
for(int e=2; e<=w+1; e++) ans*=e; //(1+w)!
printf("%lld\n",N[n+w+1]*inv(ans,mod-2)%mod*inv(n-m+w+1,mod-2)%mod);
}
}
return 0;
}
我这个人特别容易得瑟,在我想到贪心策略的时候我就已经觉得自己很牛逼了,看了数据范围就预感到了会T掉,后来蒙逼了很久才想到优化方法,但是一直很害怕逆元这个东西,怕敲。心想会做就行,不用真的敲出来。(同时内心深刻反思为什么每次自己的赛后总结都会写自己编码能力弱)然后就鼓起勇气敲了起来。加油加油加油!!!