bzoj2219 数论之神

229 篇文章 0 订阅

首先虽然题上没有说,但是可以当成保证有解来做,省掉很多麻烦的判断。
不妨记 2k+1=P P=pdii pi 是质数。对每一个 pdii 单独求解 xAB(modpdii) 的解的个数,因为每个方程得到的解都形如 xw(modpdii) ,从每个方程中任选一个解都能通过中国剩余定理求出模 P 下的通解,因此只需要把这些解的个数乘起来就行了。
接下来考虑如何求解xAB(modpd)
首先,如果 B=0 ,也就是 xA pd 的倍数,这样 x 一定是pk的倍数,其中 k 满足Akd,即 k=dA 。解的个数是 pdpk
否则的话, B 可以写成paq,其中 a0 。记 x=pky ,其中 Ak=a 。约去 pa yAq(modpda) 。对原根取对数得到 Alogylogq(modφ(pda)) ,这是一个二元一次不定方程,记 b=φ(pda) ,相邻两个解差 bgcd(A,b) ,因此解的个数是 gcd(A,b) 。一个 logy 对应一个 x ,但是注意求出的解y的范围是 [0,pda) ,而实际上 y 可以取到[0,pdk),再把答案扩大对应倍数就可以了。

#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
int A,b;
int pow(int base,int k)
{
    int ret=1;
    for (;k;k>>=1,base*=base)
        if (k&1) ret*=base;
    return ret;
}
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
int solve(int p,int d,int pd)
{
    int B=b%pd,f=1,a=0,k,phi,rt,ind,g;
    if (B==0) return pow(p,d-(d+A-1)/A);
    while (B%p==0)
    {
          B/=p;
          d--;
          pd/=p;
          a++;
    }
    k=a/A;
    phi=pd/p*(p-1);
    g=gcd(A,phi);
    return g*pow(p,a-k);
}
void solve()
{
     int k,p,m,d,ans=1,pd;
     scanf("%d%d%d",&A,&b,&k);
     p=2*k+1;
     m=sqrt(p+0.5);
     for (int i=2;i<=m;i++)
         if (p%i==0)
         {
            d=0;
            pd=1;
            while (p%i==0)
            {
                  d++;
                  p/=i;
                  pd*=i;
            }
            ans*=solve(i,d,pd);
         }
     if (p>1) ans*=solve(p,1,p);
     printf("%d\n",ans);
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--) solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值