POJ1091 简单的欧几里得+简单的容斥

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)

这个东西第一眼看真的是一脸懵逼….
先想到既然可左可右,呢么最后的结果必然是正负一
也就是存在xi使得∑ai*xi=1;
这样看就比较简单了…
虽然我对这个什么鬼的欧几里得了解的不多..
但是知道一个结论就是必然存在两个数a,b使得ac+bd=gcd(b,d);
(怎么证?啊哈哈哈哈哈哈这种东西谁会证明啊哈哈哈哈哈哈哈根本不会证啊哈哈哈哈哈哈哈哈哈…..反证法大概可以?有空试试….)
知道这个结论了以后就可以发现只要让gcd(b,d)=1即可
那么就可以用m^n减掉gcd不是1的可能就行了….
简单的想一下如何gcd不是1比较好算…
m是确定的…想要让他们互质….就不要让gcd为m的质因数的有限倍就行
然后就挨个算算..
开始容斥…

#include<iostream>
#include<cmath>
#include<memory.h>
#include<algorithm>
using namespace std;
long long yinshu[50000];
long long he[50000] = { 0 };
long long geshu[50000];
long long n, m;
int u = 0;
long long quickpower(long long a, long long b)
{
    long long res = 1;
    while (b)
    {
        if (b & 1) res *= a;
        a = a*a;
        b >>= 1;
    }
    return res;
}
void dfs(long long zuobiao,long long cengshu,long long ss)
{
    if (cengshu > u)return;
    he[cengshu] += quickpower((long long)(m / (yinshu[zuobiao] * ss)), n);
    for (long long b = zuobiao + 1;b <= u;b++)dfs(b, cengshu + 1,ss*yinshu[zuobiao]);
}
int main()
{
    while (cin >> n >> m)
    {
        memset(yinshu, 0, sizeof(yinshu));
        memset(he, 0, sizeof(he));
        memset(geshu, 0, sizeof(geshu));
        u = 0;
        long long i = m;
        for (int a = 2;a * a <= i;a++)
        {
            if (i%a==0)
            {
                yinshu[++u] = a;
                while (i%a==0)i /= a;
            }
        }
        if (i > 1)yinshu[++u] = i;
        //for (int a = 1;a <= u;a++)geshu[a] = quickpower((long long)(m / yinshu[a]), n);
        for (int a = 1;a <= u;a++)dfs(a, 1,1);
        for (int a = 1;a <= u;a++)if (a % 2)he[a] = -he[a];
        long long sum = quickpower(m, n);
        for (int a = 1;a <= u;a++)sum += he[a];
        cout << sum << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值