hdu 5976 Detachment(乘法逆元)(附测试用例)

本文探讨了在模运算中使用乘法逆元的方法,解释了为何在取模后的运算中不能直接进行除法操作,并提供了一种利用乘法逆元解决特定问题的有效途径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结来说,一个数取过模之后,他只能用逆元,不能再向以前一样.
这题的做法本身很简单,分解成2~k,就是最大.
主要就是记录下乘法逆元这个事情.
假如(a/b)%m = c
那么如果a或b是很大的,那么他们不能被直接计算出,所以要取余,那么,对a和b取余之后,(a%mb)/b就不等于c了,因为a和b都取过余了.
那么要对a,b取余时怎么办呢,就用这个叫乘法逆元的东西,(a*k)%m = c,k是b对m的乘法逆元.`

/*  xzppp  */
#include <iostream>
#include <vector>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <math.h>
#include <string>
using namespace std;
#define FFF freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define MP make_pair
#define PB push_back
typedef long long  LL;
typedef unsigned long long ULL;
const int MAXN = 100000+17;
const int MAXM = 20;
const int INF = 0x7fffffff;
const int MOD = 1e9+7;
LL add[MAXN],mul[MAXN];
LL egcd(LL a, LL b, LL& x, LL& y)
{
    LL d = a;
    if(b != 0){
        d = egcd(b, a % b, y, x);
        y -= (a / b) * x;
    }else {
        x = 1;
        y = 0;
    }
    return d;
}
LL inv(LL a, LL m)
{
    LL x, y;
    egcd(a, m, x, y);
    return (m + x % m) % m;
}
int main()
{
    #ifndef ONLINE_JUDGE 
    FFF
    #endif
    add[1] = 0; mul[1] = 1;
    for (int i = 2; i < MAXN; ++i)
    {
        add[i] = i+add[i-1];
        mul[i] = (mul[i-1]*i)%MOD;
    }
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        scanf("%d",&n);
        if(n==1)
        {
            printf("1\n");
            continue;
        }
        int l = -1,r = MAXN;
        while(r-l>1)
        {
            int mid = (r+l)>>1;
            if(add[mid]<=n)
                l = mid;
            else
                r = mid;
        }
        int sub = n - add[l];
        LL ans = -1;
        if(sub>=l-1)
            ans = (1LL*(mul[l]*inv(2,MOD))%MOD*(l+sub-(l-2)))%MOD;
        else if(sub!=0)
            ans = (1LL*mul[l+1])*inv(l-sub+1,MOD)%MOD;
        else
            ans = mul[l];
        printf("%lld\n",ans);
    }
    return 0;
}

测试代码

#define FFF freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 1e5;
const LL mod = 107;

LL add[maxn], mul[maxn];

void exgcd(LL a, LL b, LL& d, LL& x, LL& y){  //扩展欧几里得
    if(!b){ d = a; x = 1; y = 0;}
    else{
        exgcd(b, a%b, d, y, x);
        y -= x*(a/b);
    }
}

LL inv(LL a, LL n){   //求逆元
    LL d, x, y;
    exgcd(a, n, d, x, y);
    return (x+n)%n;
}

void init(){
    memset(add, 0, sizeof(add));
    memset(mul, 0, sizeof(mul));
    add[0] = add[1] = 1;
    add[2] = 2;
    mul[0] = mul[1] = 1;
    mul[2] = 2;
    for(LL i = 3; i < maxn; i++){
        add[i] = add[i-1]+i;
        mul[i] = (mul[i-1]*i)%mod;
    }
}

int main(){
    #ifndef ONLINE_JUDGE 
    FFF
    #endif
    cout<<"in"<<endl;
    init();
    cout<<mul[20]<<"  "<<mul[10]<<endl;
    LL a = 1,b=1;
    for (int i = 2; i <= 15; ++i)
    {
        a*=i;
    }
    for (int i = 2; i <= 10; ++i)
    {
        b*=i;
    }
    b = 2;
    cout<<a<<"  "<<b<<endl;
    cout<<a/b<<"  "<<(a/b)%mod<<endl;
    cout<<(a*inv(b,mod))%mod<<endl;
    cout<<(double)mul[15]/mul[10]<<endl;
    cout<<mul[15]*inv(mul[10],mod)%mod<<endl;
    cout<<(mul[15]%(mod*mul[10]))/mul[10]<<endl;
    cout<<(a%(b*mod))/b<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值