唯一分解定律

这是一篇关于如何利用唯一分解定律解决一个与概率和骰子游戏相关的问题的博客。博主面临在超市选择冰淇淋的困境,需要用公平的方式决定选择哪一种。由于时间限制,博主不能使用可能无限次数的骰子投掷,即接受-拒绝方法。于是,问题转化为找到最少次数的骰子投掷,使得每个冰淇淋被选中的概率相等。文章探讨了如何通过计算骰子面数的幂次方来整除冰淇淋数量,并利用唯一分解定律来判断是否存在这样的解决方案。如果不存在,则输出"unbounded"。

 

 

You are standing in the supermarket in front of the freezers. You have a very tough task ahead of you: you have to choose what type of ice cream you want for after dinner that evening. After a while, you give up: they are all awesome! Instead, you take your (fair) kk-sided die out of your pocket and you decide to let fate decide.

Of course, the number of ice cream choices, nn, may not be precisely kk, in which case you could not just throw the die once, rolling ii, and take the iith ice cream choice. You therefore have to use some algorithm that involves zero or more die throws that results in an ice cream choice with every choice being exactly equally likely. Being a good computer scientist, you know about the accept-reject method, which would let you make such a fair choice.

At that point, you remember that you have a very importantcompetition to attend that same afternoon. You absolutely cannot afford to be late for that competition. Because of this, you decide you cannot use the accept-reject method, as there may be no bound on the number of die throws needed to ensure a fair result, so you may end up standing there for a long time and miss the competition! Instead, you resolve to find an algorithm that is fair and uses as few dice choices as possible in the worst case.

Given nn and kk, can you determine the minimum number ii such that there is a fair algorithm that uses at most iidie throws per execution?

Input Format

On the first line one positive number: the number of test cases, at most 100. After that per test case:

  • one line with two space-separated integers nn and kk (1 \leq n, k \leq 10^91≤n,k≤109): the number of ice cream choices and the number of sides of your die, respectively.

Output Format

Per test case:

  • one line with a single integer: the smallest number of throws after which you are guaranteed to be able to make a fair choice. If there is no such number, print “unbounded” instead.

样例输入

3
4 2
2 4
3 2

样例输出

2
1
unbounded

题目来源

BAPC 2014 Preliminary

计蒜客上面的一道题,然后题目意思不太好懂。

题目意思是:有n个冰淇淋要吃,你有个骰子,k个面,问你投几次能够公平的决定出吃哪个冰淇淋,公平就是指的概率相等。

然后对于样例的 4 2 ,4个冰淇淋,骰子2面, 骰子两面记为 1,2  。那么投两次出现的情况组合分别是 1,1;1,2;2,1;2,2;

分别对应四个冰淇淋,所以投两次就可以了。

所以对于投骰子,找出组合情况数,能够整除n就行了。

简单点来说就是 k的幂次方能够整除n就行了。

但是写起来就没有这么好写了。

因为k的幂次方有可能会超过long long

因此就要用到唯一分解定律,判断他们的因子。

如果知识遗漏的,可以看一下这篇博客

https://blog.youkuaiyun.com/m0_38081836/article/details/78108166

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<map>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,k;
vector<int> v1,v2;
map<int,int> m1,m2;
bool judge( int x )
{
    int r = (int)sqrt( (double)x );
    for( int i = 2 ; i <= r ; i++ )
        if( x % i == 0 )
            return false;
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while( T-- )
    {
        v1.clear();
        v2.clear();
        m1.clear();
        m2.clear();
        scanf("%d %d",&n,&k);
        if( n == 1 )
        {
            printf("0\n");
            continue;
        }
        if( judge(n) == false )
        {
            for( int i = 2 ; i <= n ; i++ )
            {
                while( n%i == 0 )
                {
                    if( m1[i] == 0 )
                        v1.push_back(i);        //储存因子
                    m1[i]++;
                    n = n/i;
                }
            }
        }
        else        //如果是质数,只有本身一个因子
        {
            v1.push_back(n);
            m1[n]++;
        }
        if( judge(k) == false )
        {
            for( int i = 2 ; i <= k ; i++ )
                while( k%i == 0 )
                {
                    if( m2[i]%i == 0 )
                        v2.push_back(i);
                    m2[i]++;
                    k = k/i;
                }
        }
        else
        {
            v2.push_back(k);
            m2[k]++;
        }
        bool flag = true;
        int ans = 0,temp;
        for( int i = 0 ; i < v1.size(); i++ )
        {
            temp = 0;
            int t = v1[i];
            if( m2[t] == 0 )
            {                        //n的因子在k中没有,那么一定unbounded
                flag = false;
                break;
            }
            if( m1[t] <= m2[t] )    //如果k的单个因子个数大于n,则只需要一个k就行了,即目前只用投1次
            {
                temp = 1;
            }
            else
            {
                temp = m1[t]/m2[t];    // n的单个因子个数大于k,则需要除一下,不能整除要+1
                if( m1[t]%m2[t] != 0 )
                    temp++;

            }
            ans = max(temp,ans);
        }
        if( flag )
            printf("%d\n",ans);
        else puts("unbounded");
    }
    return 0;
}
/*


16 6
16 8
16 24



*/

附带上自己写的唯一分解定理模板

 

void init()							//筛选法求质数
{
    mem(prime,true);
    v.clear();

    prime[1] = false;
    for( int i = 4 ; i <= maxn ; i+=2 )
        prime[i] = false;
    for( int i = 3 ; i <= maxn ; i += 2 )
        if( prime[i] )
            for( int j = i<<1 ; j <= maxn ; j+=i )
                prime[j] = false;			//先进行判断

    for( int i = 2 ; i < maxn ; i++ )				//然后将所有质数放入vector里面
        if( prime[i] )
            v.push_back(i);
}
void decompose( int x, vector<int> &t )
{
    for( int i = 0 ; v[i]*v[i] <= x ; i++ )		//开始唯一分解定理
    {
        if( x%v[i] == 0 )
        {
            t.push_back(v[i]);
            while( x%v[i] == 0 )
                x /= v[i];
        }
    }
    if( x > 1 )					//最后还剩下本身
        t.push_back(x);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值