The Luckiest number POJ - 3696 (欧拉定理)

题目大意:对于给定的整数L,找出L能整除最短的全8序列的长度,做为Bob的幸运数字。

解析:一开始做这个题的时候直接莽夫式做法 ,枚举8的位数,交一发直接wa,想想也是,没给8的位数的上限,暴力枚举8的话肯定要爆longlong的。 。。

正确的做法居然是用欧拉定理。我们可以通过题意列出下式:8/9 * (10^x-1)=L * p
  根据欧拉定理我们知道:10^Φ(m)≡1(mod m)。 我们要做的就是把根据题目推出来的式子化成欧拉定理的式子(这个具体的推导过程真的没想出来,参考了大神的博客才懂:戳这里) 具体就不赘述了,代码描述的还是很清楚的。

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
struct node{
    ll cnt;
    ll p;
};
node num[100];
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
ll Euler(ll n){//欧拉函数
    ll ret=1,i;
    for(i=2;i*i<=n;i++){
        if(n%i==0){
            n/=i;ret*=i-1;
            while(n%i==0){
                n/=i;ret*=i;
            }
        }
    }
    if(n>1)ret*=n-1;
    return ret;
}
ll solve(ll n){//基本算数定理  用num记录下n由那些素数组成,这些素数分别有几个
    int t=0;
    for(ll i=2;i*i<n;i++){
        if(n%i==0){
            num[t].p=i;
            num[t].cnt=0;
            while(n%i==0){
                num[t].cnt++;
                n/=i;
            }
            t++;
        }
    }
    if(n>1){
        num[t].p=n;
        num[t].cnt=1;
        t++;
    }
    return t;//返回素数的种类
}
ll multi(ll a,ll b,ll c) {//由于爆int 所以用的快速乘法和快速幂
    ll ans = 0;
    while (b) {
        if (b & 1) {
            ans += a;ans %= c;
        }
        a += a;a %= c;
        b >>= 1;
    }
    return ans;
}
ll Pow(ll a, ll b, ll c) {
    ll ans = 1;
    while (b) {
        if (b & 1) {
            ans = multi(ans, a, c);
        }
        a = multi(a, a, c);
        b >>= 1;
    }
    return ans;
}

int main(){
    ll L;
    int ca=1;
    while(cin>>L,L){
        ll m=9*L/gcd(L,8);
        if(gcd(10,m)!=1){
            printf("Case %d: 0\n",ca++);
            continue;
        }
        ll pi=Euler(m);
        ll cnt=solve(pi);
        for(int i=0;i<cnt;i++){//缩小pi,找到满足条件的最小的pi
            for(int j=0;j<num[i].cnt;j++){
                if(Pow(10,pi/num[i].p,m)==1){
                    pi/=num[i].p;
                }
            }
        }
        printf("Case %d: %lld\n",ca++,pi);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您解答这个问题。首先,为了模拟微信发红包的两种发放方式,我们需要了解两种发放方式的具体实现方式。 第一种方式是“平均分配法”,即将红包金额平均分配给每个领取人。这种方式的优点是简单、公平,但缺点是可能会导致某些人领取到的金额较少,无法满足个性化需求。 第二种方式是“随机分配法”,即将红包金额随机分配给每个领取人。这种方式的优点是个性化、趣味性强,但缺点是可能会导致某些人领取到的金额较多,不够公平。 下面是两种方式的具体实现代码: 平均分配法: ```python import random def send_hongbao_1(num, money): avg_money = money / num # 平均每个人分配的金额 money_list = [avg_money for i in range(num)] # 初始化每个人的金额 return money_list ``` 随机分配法: ```python import random def send_hongbao_2(num, money): money_list = [] for i in range(num-1): # 生成一个随机数,表示当前领取人的金额比例 rate = random.uniform(0, 1) money_i = round(money * rate, 2) # 四舍五入保留两位小数 money_list.append(money_i) money -= money_i money_list.append(money) # 最后一个领取人获得剩余的金额 random.shuffle(money_list) # 打乱顺序,增加趣味性 return money_list ``` 以上两个函数分别表示了两种发放方式,其中`num`表示领取红包人数,`money`表示发放金额。这两个函数返回一个列表,表示每个领取人获得的金额。 为了显示红包发放情况,并打印红包运气王的名单,我们可以在两个函数中加入一些输出语句: ```python def send_hongbao_1(num, money): avg_money = money / num money_list = [avg_money for i in range(num)] print("红包发放情况:") for i in range(num): print("第{}个人获得了{}元".format(i+1, money_list[i])) max_money = max(money_list) luckiest = [i+1 for i, j in enumerate(money_list) if j == max_money] print("红包运气王是:", luckiest) return money_list def send_hongbao_2(num, money): money_list = [] for i in range(num-1): rate = random.uniform(0, 1) money_i = round(money * rate, 2) money_list.append(money_i) money -= money_i money_list.append(money) random.shuffle(money_list) print("红包发放情况:") for i in range(num): print("第{}个人获得了{}元".format(i+1, money_list[i])) max_money = max(money_list) luckiest = [i+1 for i, j in enumerate(money_list) if j == max_money] print("红包运气王是:", luckiest) return money_list ``` 上述代码中,`max_money`表示领取金额最多的人获得的金额数,`luckiest`表示获得最多金额的人的编号列表。 最后,如果您想从`.xlsx`表格中抽取人物,可以使用`pandas`库中的`read_excel`函数读取表格,并使用`sample`函数随机抽取人物。示例代码如下: ```python import pandas as pd df = pd.read_excel('人物表.xlsx') people_list = df['姓名'].tolist() # 获取所有人物的姓名列表 selected_list = random.sample(people_list, num) # 随机抽取num个人物 ``` 以上代码中,`num`表示需要抽取的人数。`people_list`表示所有人物的姓名列表,`selected_list`表示随机抽取的人物姓名列表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值