zoukankan      html  css  js  c++  java
  • [HNOI2002]跳蚤 【容斥】

    题目描述

    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后,显然一共有MN张不同的卡片。现在的问题是,在这所有的卡片中,有多少张可以完成任务。

    输入输出格式

    输入格式:

    输入文件有且仅有一行,包括用空格分开的两个整数N和M。

    输出格式:

    输出文件有且仅有一行,即可以完成任务的卡片数。

    1NM1081le Nle Mle 10^81NM108,且MN1016MNle 10^{16}MN1016

    输入输出样例

    输入样例#1: 复制
    2 4
    输出样例#1: 复制
    12

    说明

    这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)



    题解

    这道题解题的思维量不小,且涵盖了较多数论知识点,是一道好题,记录下来【02年省选题就那么难了么QAQ】

    由N + 1个数组合能跳到左边一格,由扩欧我们知道,这是互质的充要条件
    所以M和前N个数至少有一对互质

    直接讨论发现很麻烦,我们就反过来,用总方案 - 所有数不互质的方案数
    总方案M^N个很明显了,如果所有数不互质,它们至少有一个公共的质因子,所以我们枚举M的质因子
    假设M = 30 = 2 * 3 * 5
    我们设它们共有2,就总共有(M/2)^N种可能【M/2表示M中有多少2的倍数】
    我们设它们共有3,就总共有(M/3)^N种可能
    我们设它们共有5,就总共有(M/5)^N种可能

    不对啊,好像减多了,那么就两两组合,再加上去,加多了就三三组合减回去........

    没错,就是容斥原理

    具体实现时,质因子分解用快速分解法O(√M)分解,
    容斥时我们枚举二进制数进行容斥

    搞完啦~

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define fo(i,x,y) for (int i = (x); i <= (y); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 1005,maxm = 100005,INF = 1000000000;
    
    LL N,M;
    int fac[maxn],faci = 0;
    
    void Sp(){
    	LL e = M;
    	for (LL i = 2; i * i <= e; i++){
    		if (e % i == 0){
    			fac[++faci] = i;
    			while (e % i == 0) e /= i;
    		}
    	}
    	if (e - 1) fac[++faci] = e;
    }
    
    LL qpow(LL a,LL b){
    	LL ans = 1;
    	for (; b; b >>= 1, a *= a)
    		if (b & 1) ans *= a;
    	return ans;
    }
    
    LL cal(int s){
    	LL mult = 1,pos = 1;
    	for (int i = 1; s; i++,s >>= 1){
    		if (s & 1){
    			mult *= fac[i];
    			pos *= -1;
    		}
    	}
    	return qpow(M/mult,N) * pos;
    }
    
    void solve(){
    	Sp();
    	LL tot = qpow(M,N),maxv = ((LL)1 << faci) - 1;
    	for (int s = 1; s <= maxv; s++)
    		tot += cal(s);
    	cout<<tot<<endl;
    }
    
    int main()
    {
    	cin>>N>>M;
    	solve();
    	return 0;
    }
    


  • 相关阅读:
    效率较高的排序算法
    django进阶
    django报错TypeError: __init__() missing 1 required positional argument: 'on_delete'
    DjangoORM基本增删改查
    C++中关键字static的作用
    Sqlite的安装和使用 (windows,C#)
    sqlserver查询时对于字符串类型的数据是否区分大小写
    C#自己无聊写的2048小游戏
    C#自己无聊写的俄罗斯方块游戏
    C#实现非枚举类型的在属性控件中可下拉选择(二)
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282841.html
Copyright © 2011-2022 走看看