HNOI2002跳蚤--容斥原理
来源:互联网 发布:栖霞商务区 网络问政 编辑:程序博客网 时间:2024/05/21 11:12
题目描述:读入n,m两个数,假设一个合法的数列是n+1位,且前n位不大于m,第n+1位为m。对于每一个数列,跳蚤可以选取任意一个数列中的数k,往左或右走k步(可以走多次),若使用这一个数列跳蚤可以到达左边一步的位置,那么这一个数列就是可以完成任务的数列。现在需要求出可以完成任务的数列的总数。
分析:题目需要找出所有能够到达左边一步位置的方案总数,能够到达左边一步,就相当于数列中所有数的最大公约数为1(可以通过扩欧推出),那么我们就转化成这样一个问题,取n个不大于m的数(位置不同也算不同方案),使得他们和m的最大公约数为1。
想到这一步,我们可以把问题转化为:所有合法数列的总数(m个数放到n位,共有m的n次方种)减去数列的最大公约数大于1的总数。
我们可以这么做:将m质因数分解,枚举m的质因数t,那么1到m之间有m/t个t的倍数,把数列中全都是这些m/t个数的方案数减去即可。
然而这种方法是存在问题的,有可能会重复减去同一种方案(6的倍数会同时在2的倍数和3的倍数时都减),所以需要枚举m的所有质因数的组合方式,记录每种组合的元素个数为tot,乘积为tmp,若tot是奇数,那么减去m/tmp个数放到n位里的方案个数,否则加上m/tmp个数放到n位里的方案个数(共有m/tmp的n次方种),这就是大名鼎鼎的容斥原理啊!
代码还是很短的。
#include<iostream>#include<cstdio>using namespace std;typedef long long LL;int a[30],n,m;LL ans;LL pow(LL x,int y){ LL ans=1; while(y){ if(y&1)ans*=x; x*=x; y>>=1; } return ans;}void solve(){ int k=m; for(int i=2;i*i<=k;i++) if(k%i==0){ a[++a[0]]=i; while(k%i==0)k/=i; } if(k>1)a[++a[0]]=k; for(LL i=1;i<(1<<a[0]);i++){ int tmp=1,tot=0; for(int j=1;j<=a[0];j++) if(i&(1LL<<(j-1))) tot++,tmp*=a[j]; if(tot&1)ans-=pow(m/tmp,n); else ans+=pow(m/tmp,n); }}int main(){ scanf("%d%d",&n,&m); ans=pow(m,n); solve(); printf("%LLd\n",ans); return 0;}
1 3
- HNOI2002跳蚤--容斥原理
- [HNOI2002]跳蚤 【容斥】
- PKU 1091 跳蚤 数论 容斥原理
- poj 1091 跳蚤 (数论,容斥原理)
- 跳蚤 - POJ 1091 容斥原理
- POJ 1091 跳蚤 容斥原理
- POJ 1091 跳蚤(容斥原理)
- poj 1091 跳蚤(容斥原理)
- poj 1091 跳蚤(最大公约数原理+容斥原理)
- poj1091跳蚤---------容斥
- POJ1091 跳蚤 【容斥】
- POJ 1091 跳蚤 数论-容斥原理、扩展欧几里得
- POJ 1091 跳蚤 数论-容斥原理、扩展欧几里得
- poj 1091 跳蚤 扩展欧几里得性质+容斥原理
- POJ1091 跳蚤 素因子分解+容斥原理
- poj 1091 跳蚤 扩展欧几里得+容斥原理
- POJ 1091 跳蚤 [容斥原理]【组合数学】
- POJ 1091 - 跳蚤 - 容斥原理 +扩展欧几里德+高精度
- java常用类
- RecyclerView的基本用法
- java基础-instanceof
- 瞎想一波
- g++和gcc的相同点和区别
- HNOI2002跳蚤--容斥原理
- 对象作用域与Servlet事件监听器
- java IO流
- GITHUB自学系列之三「GIT 速成」
- HTML——eeasyUi界面学习笔记
- 文件拷贝(IFileOperation::CopyItem)
- 通过Cookie保存并读取用户登录信息
- C/C++ 笔试题汇总---字符串类
- Keil MDK从未有过的详细使用讲解