1325 - Distributing Chocolates

1325 - Distributing Chocolates
Time Limit: 4 second(s)Memory Limit: 32 MB

I have bought n chocolates for my young cousins. Every chocolate is different. So, in the contest I added the problem that how many ways I can distribute the chocolates to my K cousins. I can give more chocolates to some cousins, and may give no chocolate to some. For example, I have three cousins and I bought 2 chocolates a and b. Then I can distribute them in the following 9 ways:

No.

Cousin 1

Cousin 2

Cousin 3

1

a, b

 

 

2

 

a, b

 

3

 

 

a, b

4

a

b

 

5

a

 

b

6

 

a

b

7

b

a

 

8

b

 

a

9

 

b

a

Now as the result can be large, I asked for the result modulo 100 000 007 (a prime). But after that I found that this problem is easier than I thought. So, I changed the problem a little bit. I will give you the number of my cousins K and the result modulo 100 000 007. Your task is to find the number of chocolates I have bought. If there are several solutions, you have to find the minimum one.

Input

Input starts with an integer T (≤ 1000), denoting the number of test cases.

Each case starts with a line containing two integers K (2 ≤ K ≤ 107and result (0 ≤ result < 100000007). You can assume that the input data is valid, that means a solution exists.

Output

For each case, print the case number and the minimum possible number of chocolates I have bought.

Sample Input

Output for Sample Input

2

3 9

2 100

Case 1: 2

Case 2: 23502611

 

用到了数论中的baby-step giant-step算法

这个算法就是为了求a的x次方对p取余等于d 求x的值

#include <cstdio>
#include <map>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod=100000007;
typedef long long LL;
LL Qpow(LL n,LL m){
    LL ans=1; LL base=n;
    while(m){
        if(m&1)
            ans=(ans*base)%mod;
        base=(base*base)%mod;
        m>>=1;
    }
    return ans;
}
int main(){
    int T; scanf("%d",&T); int kcase=1;
    while(T--){
        int k; int result;
        scanf("%d %d",&k,&result);
        map<int,int> M;
        LL m=ceil(sqrt(mod));
        LL x=1;
        for(int i=0;i<=m;i++){
            M[x]=i;  x=(x*k)%mod;
        }
        LL t=Qpow(Qpow(k,mod-2),m);
        for(int i=0;i<=m;i++){
            if(M.find(result)!=M.end()){
                printf("Case %d: %d\n",kcase++,m*i+M[result]);
                break;
            }
            result=(result*t)%mod;
        }
    }
    return 0;
}

再贴一个EXGCD的
#include <cstdio>
#include <map>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod=100000007;
typedef long long LL;
LL p,q;
LL Qpow(LL n,LL m){
    LL ans=1; LL base=n;
    while(m){
        if(m&1)
            ans=(ans*base)%mod;
        base=(base*base)%mod;
        m>>=1;
    }
    return ans;
}
LL EXGCD(LL a,LL b){
    if(b==0){
        p=1;q=0;
        return a;
    }
    LL r = EXGCD(b,a%b);
    LL t = p;
    p = q;
    q=t-a/b*q;
    return r;
    
}
int main(){
    int T; scanf("%d",&T); int kcase=1;
    while(T--){
        int k; int result;
        scanf("%d %d",&k,&result);
        map<LL,int> M;
        LL m=ceil(sqrt(mod));
        LL x=1;
        for(int i=0;i<=m;i++){
            M[x]=i;  x=(x*k)%mod;
        }
        LL mid=1;
        LL t=Qpow(k,m);
        for(int i=0;i<=m;i++){
            LL G=EXGCD(mid,mod);
            p=(p*result/G%mod+mod)%(mod/G);
            if(M.find(p)!=M.end()){
                printf("Case %d: %lld\n",kcase++,m*i+M[p]);
                break;
            }
            mid=(mid*t)%mod;
        }
    }
    return 0;
}
又找到了不互诉的求法的说明
终于稍微有点空了。。 
我们来看这个方程:  
这里写图片描述  
a,b,p为常数且在int内。 
注意到这次p可以为合数。 
先来说说p为质数或者合数有什么问题。 
对于a与p互质,那么有a^phi(p)=1(mod p),对于p是素数phi(p)==p-1,所以x的取值只要在0->n-2之中取就可以了.然而如果p为合数,phi(p) < p-1,这个范围不明确,就不好分块了。而且解是否存在,有几个,也很麻烦。 
因此有extended-baby-step-giant-step算法。 
考虑a与p不互质的情况: 
对于上面的方程,我们可以考虑从x个a中拿出c个a与b和p消去公因子,直到a和p’互质为止。 
一旦互质了,那么方程就是v*a^(x-c)=b’ (mod p’),v是拿出c个a消去公因子后剩下的东西,b’,p’是消去公因子的b,p。 
这个时候还要求v的逆元,方程变为a^(x-c)=b’*v^(-1) (mod p’)。 
此时就可以用baby-step-giant-step做了,答案为BSGS的答案+c。 
注意:有可能c会大于x,所以必须约去一次就特判一次方程两边(就是v和b’)是不是相等了。如果两边相等那么直接返回c。 
附HDU2815EXBSGS裸题代码(hash表乱写的所以很慢)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
ll a,b,p,ans,hsh[70000][2];
bool ishsh[70000];
void insert(ll x,ll t)
{
    ll p=x*12580%70000;
    while(ishsh[p])p=(p+1)%70000;
    ishsh[p]=1;
    hsh[p][0]=x;
    hsh[p][1]=t;
}
int query(ll x)
{
    ll p=x*12580%70000;
    while(hsh[p][0]!=x&&ishsh[p])
        p=(p+1)%70000;
    if(!ishsh[p])return -1;
    return hsh[p][1];
}
ll gcd(ll a, ll b)
{
    return b?gcd(b,a%b):a; 
}
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(!b){x=1;d=a;y=0;}
    else
    {
        exgcd(b,a%b,d,y,x);
        y-=a/b*x;
    }
}
ll inv(ll a,ll p)
{
    ll x,y,d;
    exgcd(a,p,d,x,y);
    return (x+p)%p;
}
ll BSGS(ll a,ll b,ll p)
{
    ll m=ceil(sqrt(p)),d=1,val=1,gcd,x,y,t;
    for(int i=0;i<m;++i)
    {
        insert(val,i);
        val=val*a%p;
    }
    for(int i=0;i<m;++i)
    {
        exgcd(d,p,gcd,x,y);
        x=(b/gcd*x%p+p)%(p/gcd);
        t=query(x);
        if(t!=-1)return i*m+t;
        d=d*val%p;
    }
    return -1;
}
ll EXBSGS(ll a,ll b,ll p)
{
    ll t,c=0,v=1;
    while((t=gcd(a,p))!=1)
    {
        if(b%t)return -1;
        p/=t;//p一定要先除
        b/=t;
        v=v*a/t%p;//因为这里%p是约去后的p
        ++c;
        if(b==v)return c;//特判
    }
    b=b*inv(v,p)%p;
    ll ret=BSGS(a,b,p);
    return ret!=-1?ret+c:ret;
}
int main()
{
    while(~scanf("%I64d%I64d%I64d",&a,&p,&b))
    {
        memset(hsh,0,sizeof hsh);
        memset(ishsh,0,sizeof ishsh);
        if(b>=p)puts("Orz,I can’t find D!");//引号是全角的- -
        else if(b==0)puts("0");
        else if((ans=EXBSGS(a,b,p))==-1)puts("Orz,I can’t find D!");
        else printf("%I64d\n",ans);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值