P3868 [TJOI2009]猜数字(中国剩余定理板子)

算法:中国剩余定理(板子)+快速乘

原题链接:

戳一戳-》猜数字

原题:

题目描述

现有两组数字,每组k个,第一组中的数字分别为:a1,a2,…,ak表示,第二组中的数字分别用b1,b2,…,bk表示。其中第二组中的数字是两两互素的。求最小的非负整数n,满足对于任意的i,n - ai能被bi整除。

输入格式

输入数据的第一行是一个整数k,(1 ≤ k ≤ 10)。接下来有两行,第一行是:a1,a2,…,ak,第二行是b1,b2,…,bk

输出格式

输出所求的整数n。

输入输出样例

输入
3
1 2 3
2 3 5
输出
23
说明/提示

所有数据中,第一组数字的绝对值不超过109(可能为负数),第二组数字均为不超过6000的正整数,且第二组里所有数的乘积不超过1018

每个测试点时限1秒

注意:对于C/C++语言,对64位整型数应声明为long long,如使用scanf, printf函数(以及fscanf, fprintf等),应采用%lld标识符。

题意:

就是求一个数 X ,使它满足 对于任意的ai,bi,使X%bi=ai。然后给你多组 ai , bi ,求解X。

思路:

很明显这是一道中国剩余定理的板子题,而且题中提到第二组数据两两之间互为素数,也同时表明这是一道标准的中国剩余定理而不是拓展中国剩余定理。所以套班子就完了。然后我就愉快地WA了最后一组数据。然后看了一下题解才知道最后一组数据会爆long long,然后我又拿来了快速乘板子,然后又愉快地TLE,TLE,TLE。Orz.最后有发现了神奇的预处理数据(将数据先取模,防止数太大导致快速乘,变慢(甚至还不如直接乘))。具体那两行代码下面有标注。

AC代码:

代码注释(为了你们能看懂QAQ,给个赞吧):
moshu[]指的是用来取模的数;
yvshu[]指的是取模后的余数;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1;
ll read()///快读(见博主 分类(黑科技) 一栏)
{
    ll f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}
ll qui_mul(ll a,ll b,ll mod)
{
    ll ans=0;
    while(b)
    {
        ans=(ans+(b%2*a)%mod)%mod;
        a=(a<<1)%mod;
        b>>=1;
    }
    return ans;
}
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
    if(a==0&&b==0)
        return 0;
    if(b==0){x=1;y=0;return a;}
    ll g=ex_gcd(b,a%b,x,y),tmp=x;
    x=y;y=tmp-a/b*y;
    return g;
}
ll china(ll moshu[],ll yvshu[],int num)///要求除数必须全是质数
{
    ll gongbei=1,ans=0,temp,x,y,i;
    for(i=0;i<num;i++)
    {
        gongbei*=moshu[i];
    }
    for(i=0;i<num;i++)
    {
        temp=gongbei/moshu[i];///除了moshu[i]之外的公倍数
        ex_gcd(temp,moshu[i],x,y);///取逆元(同余模定理)
x=(x%moshu[i]+moshu[i])%moshu[i];///神奇的一行代码,TLE,TLE,哭了哭了
        ans=(ans+qui_mul(qui_mul(temp,x,gongbei),yvshu[i],gongbei))%gongbei;///因为要求出最小的合适解;
    }
    return (ans+gongbei)%gongbei;
}
int main()
{
int n;
scanf("%d",&n);
ll moshu[n],yvshu[n];
for(int i=0;i<n;i++)
{
    yvshu[i]=read();
}
for(int i=0;i<n;i++)
{
    moshu[i]=read();
}
for(int i=0;i<n;i++)
    yvshu[i]=(yvshu[i]%moshu[i]+moshu[i])%moshu[i];///(先对数据进行预处理,减少数据的大小,由于题目中可能是负数所以还要转化成正数(好像与补码反码有关),否则就会TLE,上面原因相同)神奇的一行代码,哭了哭了,
ll ans=china( moshu,yvshu,n);
printf("%lld\n",ans);
}

总结:

这一道题虽然是一道板子题,但是我自己还是没能独立写出来,Why?
菜!!!
很多板子的适用条件都没有搞清楚,所以胡乱使用导致BUG不断。
好好学吧~~

告诫:

学就完了!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值