HDU-5976

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掉,后来蒙逼了很久才想到优化方法,但是一直很害怕逆元这个东西,怕敲。心想会做就行,不用真的敲出来。(同时内心深刻反思为什么每次自己的赛后总结都会写自己编码能力弱)然后就鼓起勇气敲了起来。加油加油加油!!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值