码迷,mamicode.com
首页 > 其他好文 > 详细

HDU - 5976 Detachment(逆元)

时间:2017-05-18 23:57:43      阅读:448      评论:0      收藏:0      [点我收藏+]

标签:mil   namespace   分析   处理   lower   UI   return   最小   scan   

题意:将一个数x拆成a1+a2+a3+……,ai不等于aj,求最大的a1*a2*a3*……。

分析:

1、预处理前缀和前缀积,因为拆成1对乘积没有贡献,所以从2开始拆起。

2、找到一个id,使得2+3+4+……+id - 1(sum[id-1]) < x < 2+3+4+……+id(sum[id)。(二分找即可)

则rest = x - sum[id - 1]。将rest分配给2+3+4+id-1中的某个数。

3、在保证数字不重复的前提下,分配给的那个数越小越好,证明见4。

因此,应该分配给的数为id-rest。但是在id-rest小于2时,那还应该分配给2,2是可以分配的数字中最小的数字。

假设分配给4,那么最后的结果中,mul[id-1]应除以4(把4去掉),然后再乘上(4+rest)。

4、证明:设tmp=2*3*4*……*(id - 1)。

假设既可分配给4,也可分配给5的情况下,

将rest分配给4:设tmp=4*t1,则ans1=(4+rest)*t1,

将rest分配给5:设tmp=5*t2,则ans2=(5+rest)*t2,

因为t1>t2,所以ans1>ans2,得证。

5、PS:2为偶数,3为奇数,2x+3y可以表示大于1的所有正整数,3最多的时候最优。

6、逆元:

1、除法取模要用逆元。

遇到(a/b)%mod这种情况,应转化成(a*k)%mod,k即为a在mod情况下的逆元。

2、递推求逆元

inv[1]=1
for(i=2;i<n;i++)
inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD

3、定义:
满足b*k≡1 (mod MOD)   即b*k%MOD==1%MOD==1的k值就是b关于MOD的乘法逆元。

4、证明:

因为b*k≡1 (mod MOD),即(b*k)%MOD=1,即b*k=MOD*x+1。

所以,k=(MOD*x+1)/b。

把k代入(a*k) mod MOD,得:
(a*(MOD*x+1)/b) mod MOD
=((a*MOD*x)/b+a/b) mod MOD
=[((a*MOD*x)/b) mod MOD +(a/b)] mod MOD
=[(MOD*(a*x)/b) mod MOD +(a/b)] mod MOD
因为p*[(a*x)/b] mod p=0

所以上式=(a/b)mod MOD,得证。

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100000 + 10;
typedef long long LL;
LL sum[MAXN], mul[MAXN], inv[MAXN];
const LL MOD = 1e9 + 7;
void init(){
    sum[1] = 0, mul[1] = 1, inv[1] = 1;
    for(int i = 2; i < MAXN; ++i){
        sum[i] = sum[i - 1] + i;
        mul[i] = ((mul[i - 1] % MOD) * (i % MOD)) % MOD;
        inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
    }
}
int main(){
    int T;
    scanf("%d", &T);
    init();
    while(T--){
        LL x;
        scanf("%lld", &x);
        if(x == 1){
            printf("1\n");
            continue;
        }
        int id = lower_bound(sum + 2, sum + MAXN, x) - sum;
        if(sum[id] == x){
            printf("%lld\n", mul[id]);
            continue;
        }
        --id;
        LL rest = x - sum[id];
        LL ans;
        if(2 + rest > id){
            ans = ((mul[id] * inv[2]) % MOD * (2 + rest)) % MOD;
        }
        else{
            ans = ((mul[id] * inv[id + 1 - rest]) % MOD * (id + 1)) % MOD;
        }
        printf("%lld\n", ans % MOD);
    }
    return 0;
}

  

HDU - 5976 Detachment(逆元)

标签:mil   namespace   分析   处理   lower   UI   return   最小   scan   

原文地址:http://www.cnblogs.com/tyty-Somnuspoppy/p/6876132.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!