容斥题

Posted sparks-pion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了容斥题相关的知识,希望对你有一定的参考价值。

题目描述

N 个小朋友围成一圈,你有无穷个糖果,想把其中一些分给他们。
从某个小朋友开始,我们顺时针给他们标号为 1 ~ N 。第(i)个小朋友可以得到至多 (a[i]),至少 1 个糖果。
问有多少种分配方案使得每一对相邻的小朋友拿到的糖果数不同。答案对(10^9+7)取模。

输入描述:

第一行一个整数 N。
接下来一行 N 个整数,第 i 个数表示 a[i]。

输出描述:

一行一个整数,表示答案。

  • 输入1

3
3 3 3
  • 输出1

6
  • 输入2

4
4 4 4 4
  • 输出2

84

数据范围:

[n≤10^6,a[i]≤10^9]
题解
================
(f[i])([1,i]) 满足条件的方案数,先考虑一条链,那么由(f[i?1])递推到(f[i])的公式为
[f[i?1]?A[i]f[i?1]?A[i]]但是这样显然会有重复的,而且只存在第i项和第i-1项重复的情况,那就减去[f[i?2]?min(A[i],A[i?1])]但是这样又会把第i项,第i-1项,第i-2项都相同的情况给减掉,所以再加上[f[i?3]?min(A[i],A[i?1],A[i-2])]所以得到
[f[i]=sum_{j=0}^{j<i}f[j]*min(A[i],A[i-1],dots,A[j+1])*(-1)^{i-j-1}]
[f[i]=(-1)^{i}*sum_{j=0}^{j<i}f[j]*min(A[i],A[i-1],dots,A[j+1])*(-1)^{j+1}]
我们发现[min(A[i],A[i-1],dots,A[j+1])]
发现后面很多段f[i]的系数是一个值,而且这个值是按位置递增的,可以用单调栈搞一下。
怎么搞到环上?减去第一段和最后一段相等的情况。
为了方便,让第一段为最小的元素,这样可以用(a1)统计方案了
这里我没有用到特别容斥的方案来理解
首先,长度为2的链直接就是一个环了
长度为3的链减去长度为2的环就可以拼成环了
原理是对第三个位置填上和第一个位置相等的元素,每种情况只能填一个,(a1)最小保证一定有的填
类推 长度为(N)的链减去一个长度为(n?1)的环可以拼成一个长为(n)的环,复杂度(O(n))

code

#include <bits/stdc++.h>
#define int long long
#define re register int
#define inf 1e18
using namespace std;
inline void read(int &x){
    x=0;char ch=getchar();
    for(;!isdigit(ch);ch=getchar());
    for(; isdigit(ch);ch=getchar())
        x=(x<<1)+(x<<3)+(ch^48);
}
const int N=1000010,P=1e9+7;
int a[N],b[N],mn[N],f[N],dp[N],s[N],n,p,cnt,ans,sum;
signed main(){
    read(n),a[0]=inf;
    for(re i=1;i<=n;++i)read(a[i]),p=(a[i]<a[p])?i:p;
    while(cnt!=n)b[++cnt]=a[p],p=p%n+1;p=0;
    f[1]=dp[0]=P-1,dp[1]=b[1],p=s[1]=1;
    for(re tmp=0,i=2;i<=n;++i,tmp=0){
        while(p&&b[s[p]]>=b[i])(tmp+=f[s[p--]])%=P;
        if(p) dp[i]=(s[p]&1?(P-dp[s[p]]):dp[s[p]]);
        (dp[i]+=tmp*b[i]%P)%=P;
        (dp[i]+=(dp[i-1]*b[i]%P*(i&1?-1:1)+P))%=P;
        dp[i]=(dp[i]*(i&1?-1:1)+P)%P; 
        f[s[++p]=i]=(tmp+dp[i-1]*(i&1?-1:1)+P)%P;
    }
//  for(re i=1;i<=n;++i) printf("f:%lld
",f[i]);
//  for(re i=1;i<=n;++i) printf("dp:%lld
",dp[i]);
    for(re i=n;i>=2;--i) (ans+=((n-i)&1?P-dp[i]:dp[i]))%=P;
    printf("%lld",ans);
    return 0;
}

以上是关于容斥题的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4517: [Sdoi2016]排列计数容斥原理+组合数学

51nod1251 Fox序列的数量

题解-bzoj2560 串珠子

bzoj1042--容斥原理+完全背包

bzoj1042硬币购物——递推+容斥

hdu 5212 反向容斥或者莫比