容斥原理算法总结(bzoj 2986 2839)

容斥原理是一个从小学就开始学习的算法。但是很多难题现在都觉得做的十分吃力。

容斥原理大概有两种表现形式,一种是按照倍数进行容斥,这个东西直接用莫比乌斯函数就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 200100
typedef long long qword;
bool pflag[MAXN];
int prime[MAXN],topp=-1;
int mu[MAXN];
int a[MAXN],tota;
int b[MAXN],totb;
void init()
{
        for (register int i=2;i<MAXN;i++)
        {
                if (!pflag[i])
                {
                        prime[++topp]=i;
                        mu[i]=1;
                }
                for (register int j=0;j<=topp && i*prime[j]<MAXN;j++)
                {
                        pflag[i*prime[j]]=true;
                        if (i%prime[j]==0)
                        {
                                mu[i*prime[j]]=0;
                                break;
                        }
                        mu[i*prime[j]]=-mu[i];
                }
        }
}

int main()
{
        //freopen("input.txt","r",stdin);
        qword tot;
        scanf("%lld\n",&tot);
        init();
        for (register int i=1;i<MAXN;i++)
                if (mu[i]==1)
                        a[tota++]=i;
                else if (mu[i]==-1)
                        b[totb++]=i;
        register qword l,r,mid;
        register qword ans=0;
        l=0,r=26000000000LL;
        while (l+1<r)
        {
                mid=(l+r)>>1;
                ans=0;
                for (register int i=0;i<tota && (qword)a[i]*a[i]<=mid;i++)
                        ans=ans+mid/((qword)a[i]*a[i]);
                for (register int i=0;i<totb && (qword)b[i]*b[i]<=mid;i++)
                        ans=ans-mid/((qword)b[i]*b[i]);
                if (ans>=tot)
                        r=mid;
                else
                        l=mid;
        }
        printf("%lld\n",r);

}

bzoj 2986

另一种可以理解为一个一个递推,按照+/-1容斥。

  bzoj 2839 : 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)

  这道题虽然说懂了正解,但是还是没有弄清楚最初的做法为什么错了。

  考虑求大于等于i的方案数,可理解为从n个选出i个,再在另n-i个里面任意选择,由于答案的k个肯定属于这i个,所以容斥时再乘上系数C(i,k),直接容斥即可。

  这种题如果方法有问题其实是很难检查出来的,最好的方法是写暴力或者用另一种思路写。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1000100
#define MOD 1000000007
typedef long long qword;
qword fact[MAXN];
qword pow_mod(qword x,qword y)
{
        qword ret=1;
        while (y)
        {
                if (y&1)
                        ret=ret*x%MOD;
                x=x*x%MOD;
                y>>=1;
        }
        return ret;
}
qword finv[MAXN];
#define C(x,y) (fact[x]*finv[y]%MOD*finv[(x)-(y)]%MOD)

int main()
{
        freopen("input.txt","r",stdin);
        int n,m;
        scanf("%d%d",&n,&m);
        fact[0]=1;
        for (register int i=1;i<=n;i++)
                fact[i]=fact[i-1]*i%MOD;
        finv[n]=pow_mod(fact[n],MOD-2);
        for (register int i=n-1;i>=0;i--)
                finv[i]=finv[i+1]*(i+1)%MOD;
        register qword ans=0;
        register qword tmp=2;
        ans+=((n-m)%2==0?1:-1)*C(n,n)*tmp%MOD*C(n,m)%MOD;
        for (register int i=n-1;i>=m;i--)
        {
                tmp=tmp*tmp%MOD;
                ans+=((i-m)%2==0?1:-1)*C(n,i)*tmp%MOD*C(i,m)%MOD;
                ans%=MOD;
        }
        //ans=h[m]*C(n,m);
        printf("%lld\n",ans);
}

bzoj 2839

  bzoj 1042:硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。

  很早以前做的一道经典题目,其思路很有借鉴意义。

时间: 2024-10-31 22:21:34

容斥原理算法总结(bzoj 2986 2839)的相关文章

【BZOJ 2986】 莫比乌斯函数+容斥原理

2986: Non-Squarefree Numbers Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 337  Solved: 156 Description 一个正整数K被称为squarefree,如果它没有一个D^2(D>1)这样的约数. Input 读入一个正整数N Output 找出第N个不是squarefree的数.1<=N<=10^10 Sample Input 10 Sample Output 27 Hint 前10个非s

大步小步算法 模板bzoj 计算器

你被要求设计一个计算器完成以下三项任务: 1.给定y,z,p,计算Y^Z Mod P 的值: 2.给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数: 3.给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数. code: // #include<bits/stdc++.h> using namespace std; #define ll long long ll T,p; ll ksm(ll a,ll b,ll c) { ll ans=1; while(b

BZOJ 2839 集合计数 容斥原理

题目大意:给定n个元素,求交集大小为k的集合的集合共有多少种 考虑容斥原理 计算交集大小至少为i的集合有多少种 首先需要选出i个元素 方案为C(n,i) 其它2^(n-i)个集合每个可选可不选 一共2^[2^(n-i)]种 故答案为Σ[k<=i<=n]C(n,i)C(i,k)*2^[2^(n-i)] #include <cstdio> #include <cstring> #include <iostream> #include <algorithm&

BZOJ 3622(已经没有什么好害怕的了-Dp+容斥原理)

3622: 已经没有什么好害怕的了 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 7  Solved: 6 [Submit][Status] Description Input Output Sample Input 4 2 5 35 15 45 40 20 10 30 Sample Output 4 HINT Source 2014湖北省队互测week2 PS:本题的数据中能量互不相同. 1.我们计算出糖果>药片的组数=k 2.我们计算出f[

[hdu5213]容斥原理+莫队算法

题意:给一个序列a,以及K,有Q个询问,每个询问四个数,L,R,U,V, 求L<=i<=R,U<=j<=V,a[i]+a[j]=K的(i, j)对数(题目保证了L <= R < U <= V). 思路:首先用容斥原理把询问变为i,j同区间,记f(A,B)为答案,'+'为区间的并,A=[L,R],B=[U,V],C=[u+1,v-1],则f(A,B) = f(A+B+C,A+B+C)+f(C,C)-f(A+C,A+C)-f(B+C,B+C).令g(L,R) = f(

bzoj 2005 能量采集 - 容斥原理

栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后, 栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起. 栋栋的植物种得非常整齐,一共有n列,每列 有m棵,植物的横竖间距都一样,因此对于每一棵植物,栋栋可以用一个坐标(x, y)来表示,其中x的范围是1至n, 表示是在第x列,y的范围是1至m,表示是在第x列的第y棵. 由于能量汇集机器较大,不便移动,栋栋将它放在了 一个角上,坐标正好是(0, 0). 能量汇集机器在汇集的过程中有一定的能量

bzoj 4810 由乃的玉米田 - bitset - 莫队算法

由乃在自己的农田边散步,她突然发现田里的一排玉米非常的不美.这排玉米一共有N株,它们的高度参差不齐. 由乃认为玉米田不美,所以她决定出个数据结构题 这个题是这样的: 给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是 否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1 ,2,3选出的这两个数可以是同一个位置的数 Input 第一行两个数n,m 后面一行n个数表示ai 后面m行每行四个数op

BZOJ 3680: 吊打XXX【模拟退火算法裸题学习,爬山算法学习】

3680: 吊打XXX Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 3192  Solved: 1198[Submit][Status][Discuss] Description gty又虐了一场比赛,被虐的蒟蒻们决定吊打gty.gty见大势不好机智的分出了n个分身,但还是被人多势众的蒟蒻抓住了.蒟蒻们将 n个gty吊在n根绳子上,每根绳子穿过天台的一个洞.这n根绳子有一个公共的绳结x.吊好gty后蒟蒻们发现

Pollard rho算法+Miller Rabin算法 BZOJ 3668 Rabin-Miller算法

BZOJ 3667: Rabin-Miller算法 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 1044  Solved: 322[Submit][Status][Discuss] Description Input 第一行:CAS,代表数据组数(不大于350),以下CAS行,每行一个数字,保证在64位长整形范围内,并且没有负数.你需要对于每个数字:第一,检验是否是质数,是质数就输出Prime 第二,如果不是质数,输出它最大的质因子是哪个. O