北大poj-1091

跳蚤

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 9591 Accepted: 2892

Description

Z 城市居住着很多只跳蚤。在Z城市周六生活频道有一个娱乐节目。一只跳蚤将被请上一个高空钢丝的正中央。钢丝很长,可以看作是无限长。节目主持人会给该跳蚤 发一张卡片。卡片上写有N+1个自然数。其中最后一个是M,而前N个数都不超过M,卡片上允许有相同的数字。跳蚤每次可以从卡片上任意选择一个自然数S, 然后向左,或向右跳S个单位长度。而他最终的任务是跳到距离他左边一个单位长度的地方,并捡起位于那里的礼物。
比如当N=2,M=18时,持有卡片(10, 15, 18)的跳蚤,就可以完成任务:他可以先向左跳10个单位长度,然后再连向左跳3次,每次15个单位长度,最后再向右连跳3次,每次18个单位长度。而持 有卡片(12, 15, 18)的跳蚤,则怎么也不可能跳到距他左边一个单位长度的地方。
当确定N和M后,显然一共有M^N张不同的卡片。现在的问题是,在这所有的卡片中,有多少张可以完成任务。

Input

两个整数N和M(N <= 15 , M <= 100000000)。

Output

可以完成任务的卡片数。

Sample Input

2 4

Sample Output

12

Hint

这12张卡片分别是:
(1, 1, 4), (1, 2, 4), (1, 3, 4), (1, 4, 4), (2, 1, 4), (2, 3, 4),
(3, 1, 4), (3, 2, 4), (3, 3, 4), (3, 4, 4), (4, 1, 4), (4, 3, 4)

Source

 
分析:很经典很经典的数论题目,为了做这道题目真是又学习了一把 欧几里得原理 和 容斥原理。这道题目学习为主。
参考:http://blog.csdn.net/crescent__moon/article/details/19327879?utm_source=tuicool&utm_medium=referral
解题:

给你两个正整数n,m,让你求长度为n+1的满足条件的一个等式:a[1]*x1+a[2]*x2+a[3]*x3+...+a[n]*xn+a[n+1]*x(n+1)=1 (0<=a[i]<=m&&a[n+1]=m)

让你求一共有多少种情况满足这个条件。

要使得 a[1]*x1+a[2]*x2+a[3]*x3+...+a[n]*xn+a[n+1]*m=1 (0<=a[i]<=m),那么a[1],a[2],a[3]....a[n+1]的最大公约数为1.

要解决此题,你需要知道的知识有扩展欧几里得,鸽巢原理,以及递归求所有的排列组合。

许多博客都举了这么一个例子:

例如:n=2,m=360 
360=3^2*2^3*5  所有不满足条件的数列,最大公约数是360质因子的乘积,只要将这些组合去掉,就是要求的答案(不懂的慢慢揣摩)

那么就要先求出m的所有质因子,然后求出总的排列组合的个数,即题目中说的M^N,最后根据鸽巢原理求得最后答案。

公式为:ans=M^N-(有奇数个公因数的n元组)+(有偶数个公因数的n元组)。拿上面的例子来说就是

ans=m^n-( 有公因数2的n元组)- (有公因数3的n元组)- (有公因数5的n元组)+ (有公因数2,3的n元组) +(有公因数2,5的n元组)+ (有公因数3,5的n元组)- (有公因数2,3,5的n元组).

有公因数d的n元组,每个位置上有 (m/d)个选择(1 ~ m里面有m/d个d的倍数),根据乘法原理,可以得出有公因数d的n元组有 (m/d)^n 个.
 
 1 //容斥原理  + 欧几里得原理
 2 #include<stdio.h>
 3 
 4 #define M 100000
 5 
 6 long long factors[M],reorder[M];
 7 long long n,m,factorNum,per;
 8 
 9 void factoring()//分解质因子,存在factors里面
10 {
11     factorNum=0;
12     long long max=m;
13     int i = 0;
14     for(i=2;i*i<=max;i++)
15     {
16         if(max%i==0)factors[factorNum++]=i;
17         while(max%i==0)max/=i;
18     }
19     if(max!=1)factors[factorNum++]=max;
20 }
21 
22 long long power(long long base, long long index)//求x^y
23 {
24     long long k=base;
25     long long i = 0;
26     for(i=1; i<index; i++)
27         base*=k;
28     return base;
29 }
30 
31 void dfs(long long start,long long pos,long long FactorNum4Reorder)
32 {
33     long long i = 0;
34     if(pos==FactorNum4Reorder)
35     {
36         long long t=m;
37         for(i=0; i<FactorNum4Reorder; i++)
38         {
39             t/=reorder[i];//t表示每位上有几个包含质因子的数
40         }
41         per+=power(t,n);//总共有多少个
42     }
43     else
44     {
45         for(i=start; i<factorNum; i++)//递归回溯求解所有排列组合
46         {
47             reorder[pos]=factors[i];
48             dfs(i+1,pos+1,FactorNum4Reorder);
49         }
50     }
51 }
52 
53 int main()
54 {
55     long long i = 0;
56     while(scanf("%I64d%I64d",&n,&m)!=EOF)
57     {
58         factoring();
59         long long ans=power(m,n);
60         for(i=1; i<=factorNum; i++)
61         {
62             per=0;
63             dfs(0,0,i);
64             if(i%2)ans-=per;//如果有奇数个公因数的n元组就相减
65             else ans+=per;//如果有奇数个公因数的n元组就相加
66         }
67         printf("%I64d\n",ans);
68     }
69     return 0;
70 }

 

转载于:https://www.cnblogs.com/bixiongquan/p/5629370.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值