[ACM Day1]BAPC2014 A.Choosing Ice Cream

题目描述

有一个k面的骰子,用起选出N种不同的物品,并且保证每个物品选到的概率相同如果能输出最小投掷数,如果不能输出“unbounded”。

数据范围

n,k<=109 n , k <= 10 9

题目分析

纠结了半天,在dalao的帮助下终于想明白了,就是用这个k面骰投 ans a n s 的结果对 n n 去映射,确保每个物品的概率相同即可。于是我们可以将这个问题转化成

kans0modn

由于 ans a n s 的值很小,所以直接枚举就可以了,模糊的上界约为30,所以如果三十没有出解就是无解。代码写的EX-BSGS,真的蠢。。。

#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
    char ch = getchar();
    int x = 0 , f = 1 ;
    while( !isdigit( ch ) )
           if( ch == '-' ) f = -1 , ch = getchar();
           else ch = getchar();
    while( isdigit( ch ) )
           x = (ch  - '0') + x * 10 , ch =  getchar();
    return x * f;
}
int gcd( int a , int b ){
    return 0 == b ? a : gcd( b , a % b );
}
const int N = 140142;
typedef long long ll;
struct Hash_Set
{
    ll head[N], next[N], X[N], val[N], tot;
    void clear()
    {
        memset(head, 0, sizeof(head));
        memset(next, 0, sizeof(next));
        memset(val, -1, sizeof(val));
        memset(X, 0, sizeof(X));
        tot = 0;
    }
    ll& operator [](ll x)
    {
        ll index = x%N;
        for (ll i = head[index]; i; i = next[i])
        {
            if (X[i] == x)
                return val[i];
        }
        next[++tot] = head[index];
        head[index] = tot;
        X[tot] = x;
        return val[tot];
    }
}hash1;
ll pow(ll x, ll y, ll mod)
{
    ll ret = 1;
    while (y)
    {
        if (y & 1)
            ret = ret*x%mod;
        x = x*x%mod;
        y >>= 1;
    }
    return ret;
}
ll gcd(ll a, ll b)
{
    ll t = a%b;
    while (t)
    {
        a = b, b = t;
        t = a%b;
    }
    return b;
}
void exgcd(ll a, ll b, ll &x, ll &y)
{
    if (!b)
        x = 1, y = 0;
    else
    {
        exgcd(b, a%b, y, x);
        y -= a / b*x;
    }
}
ll inv(ll t, ll mod)
{
    ll x, y;
    exgcd(t, mod, x, y);
    return (x%mod + mod) % mod;
}
ll BSGS(ll A, ll B, ll C)
{
    hash1.clear();
    ll bk = ceil(sqrt(C)), i, j, k, D, temp;
    for (i = 0, D = 1; i < bk; i++, D = D*A%C)
    {
        if (hash1[D] == -1)
            hash1[D] = i;
    }
    temp = inv(D, C);
    for (i = 0, k = B; i <= bk; i++, k = k*temp%C)
    {
        if (hash1[k] != -1)
            return i*bk + hash1[k];
    }
    return -1;
}
ll EXBSGS(ll A, ll B, ll C)
{
    if(C==1)
    {
        if(!B)  return 0;
        else    return -1;
    }
    ll lg = ceil(log(C*1.0) / log(2)), i, k, mod;
    for (i = 0, k = 1; i <= lg; i++, k = k*A%C)
    {
        if (k == B)
            return i;
    }
    i = 0, mod = C;
    while ((k = gcd(A, mod)) != 1)
    {
        if (B%k)    return -1;
        B /= k, mod /= k;
        i++;
    }
    ll ret = BSGS(A, B*inv(pow(A, i, mod)*inv(C / mod, mod) % mod, mod) % mod, mod);
    if (ret != -1)
        return ret + i;
    else
        return -1;
}
int main()
{
    ll c, T, x , y , ans;
    scanf("%lld", &T);
    for (c = 1; c <= T; c++)
    {
        scanf("%lld%lld", &x , &y);
        ans = EXBSGS(y, 0, x);
        if( ans == -1 ) printf("unbounded\n");
        else printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值