FZU - 2294 &运算模拟自然溢出、快速乘

题解

Sample Input

def six 6
def abc 1
def bcd 0
sub bcd abc
add abc six
def universe 0
mul abc six
add universe abc
div bcd six
mod bcd abc

Sample Output

six = 6
abc = 1
bcd = 0
bcd = 140737488355327
abc = 7
universe = 0
abc = 42
universe = 42
bcd = 23456248059221
bcd = 5
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
const LL mod=0x00007fffffffffff;//这里比较妙啊有木有
map<string,LL>mp;
int main(){
#ifdef _DEBUG
freopen("data.in","r",stdin);
#endif // _DEBUG
    ios::sync_with_stdio(false);
    string op,var1,var2;
    LL x;
    while(cin>>op>>var1){
        if(op=="def"){cin>>x;mp[var1]=x;}
        else{
            cin>>var2;
            if(op=="add"){mp[var1]=(mp[var1]+mp[var2])&mod;}//用&代替%效率更高
            else if(op=="sub"){mp[var1]=mp[var1]-mp[var2];while(mp[var1]<0)mp[var1]+=mod+1;mp[var1]&mod;}//注意是 +mod+1
            else if(op=="mul"){mp[var1]=(mp[var1]*mp[var2])&mod;}
            else if(op=="div"){mp[var1]/=mp[var2];}
            else if(op=="mod"){mp[var1]%=mp[var2];}
        }
        cout<<var1<<" = "<<mp[var1]<<endl;
    }
    return 0;
}

其实这里我没有考虑到long long溢出,幸好数据没有卡,但是很多人都写了快速乘。

快速乘 参考链接

a*b

快速乘法的基本思想 ,是二进制和乘法分配律的结合,(浮点数不满足结合律),
比如, 13==(1101)2 13 == ( 1101 ) 2 , 413 4 ∗ 13 等于 4(1101)2 4 ∗ ( 1101 ) 2 ,用分配律展开得到 413==4(1000+100+1)2 4 ∗ 13 == 4 ∗ ( 1000 + 100 + 1 ) 2
不难观察出,快速幂可以通过判断当前的位(bit)是1还是0,推断出是否需要做求和操作,每次移动到下一位(bit)时,就对ans进行*2操作,等待是否求和。由于除以2和位移操作是等效的,因此这也可以看作是二分思想的应用,这种算法将b进行二分从而减少了不必要的运算,时间复杂度是log(n)。
当两个数相乘可能超过long long 范围的时候用,因为在加法运算的时候不会超,而且可以直接取模,这样就会保证数据超不了了

LL qmul(LL a,LL b,LL mod){
    LL ans=0;
    for(;b;b>>=1,a=(a<<1)%mod)
        if(b&1)ans=(ans+a)%mod;
    return ans;
}

LL qpow(LL base,LL n,LL mod){
    LL ans=1;
    for(;n;n>>=1,base=qmul(base,base,mod)){
        if(n&1) ans=qmul(ans,base,mod);
    }
    return ans;
}

HDU-5187 快速幂+快速乘

Input

Multiply test cases(less than 1000). Seek EOF as the end of the file.
For each case, there are two integers n and p separated by a space in a line. ( 1n,p1018 1 ≤ n , p ≤ 10 18 )

Output

For each test case, output a single line indicating the answer.

Sample Input
2 233
3 5
Sample Output
2
1
code
/**
    求解2^n-2 mod p, 1≤n,p≤10^18
    两个数相乘可能超过long long,而加法的时候不会超
*/
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;

LL qmul(LL a,LL b,LL mod){
    LL ans=0;
    for(;b;b>>=1,a=(a<<1)%mod)
        if(b&1)ans=(ans+a)%mod;
    return ans;
}
LL qpow(LL base,LL n,LL mod){
    LL ans=1;
    for(;n;n>>=1,base=qmul(base,base,mod)){//不能直接乘
        if(n&1) ans=qmul(ans,base,mod);
    }
    return ans;
}

int main(){
#ifdef _DEBUG
freopen("data.in","r",stdin);
#endif // _DEBUG
    ios::sync_with_stdio(false);
    LL n,p;
    while(cin>>n>>p){
        if(n==1) {cout<<1%p<<endl;continue;}
        cout<<(qpow(2,n,p)-2+p)%p<<endl;//这一步注意,不要为负数
    }
    return 0;
}

O(1)快速乘

注意有误差。

inline long long multi(long long x,long long y,long long mod)
{
    long long tmp=(x*y-(long long)((long double)x/mod*y+1.0e-8)*mod);
    return tmp<0 ? tmp+mod : tmp;
}
inline ll ksc(ll x,ll y,ll mod)
{
    return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;     
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值