• 容斥小结


    本篇小结大部分都是广义容斥原理,你可以看看这篇容斥原理小结,shadow;

    bzoj3622
    • 考虑糖果比药片大的对数比药片比糖果大的对数不太好考虑,我们先只考虑糖果比药片多的对数
    • 显然先排序,对每个糖果处理一个(num)表示有(num)个药片它小,设(dp[i][j])表示考虑前i个,有j对符合条件,转移方程$$dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*max(0,num[i]-j+1)$$,第一项代表不选第i个,第二项代表选,前面有(max(0,num[i]-j+1))个可以与他配对
    • 然后令(ans[i]=dp[n][i]*(n-i)!),没有配对的就直接阶乘乱放
    • 显然会算重,直接二项式定理容斥就行了
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=2000+5;
    bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
    bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
    template<typename T>T read()
    {
      T ans=0,f=1;
      char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
      return ans*f;
    }
    template<typename T>void write(T x,char y)
    {
      if(x==0)
      {
          putchar('0');putchar(y);
          return;
      }
      if(x<0)
      {
          putchar('-');
          x=-x;
      }
      static char wr[20];
      int top=0;
      for(;x;x/=10)wr[++top]=x%10+'0';
      while(top)putchar(wr[top--]);
      putchar(y);
    }
    void file()
    {
      #ifndef ONLINE_JUDGE
          freopen("3622.in","r",stdin);
          freopen("3622.out","w",stdout);
      #endif
    }
    const int mo=1e9+9;
    int n,k;
    int a[N],b[N];
    void input()
    {
    	n=read<int>(),k=read<int>();
    	k=(n+k)>>1;
    	For(i,1,n)a[i]=read<int>();
    	For(i,1,n)b[i]=read<int>();
    }
    int num[N],dp[N][N],ans[N];
    void add(int &a,int b)
    {
    	a+=b;if(a>=mo)a-=mo;
    }
    int C[N][N],mc[N];
    void init(int maxn)
    {
    	For(i,0,maxn)C[i][0]=C[i][i]=1;
    	For(i,2,maxn)For(j,1,i-1)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    	mc[0]=1;For(i,1,maxn)mc[i]=1ll*mc[i-1]*i%mo;
    }
    void work()
    {
    	int pos=0;
    	sort(a+1,a+n+1);
    	sort(b+1,b+n+1);
    	For(i,1,n)
    	{
    		while(pos<n&&b[pos+1]<a[i])++pos;
    		num[i]=pos;
    		
    	}
    	dp[0][0]=1;
    	For(i,1,n)For(j,0,i)
    	{
    		dp[i][j]=dp[i-1][j];
    		if(j)add(dp[i][j],1ll*dp[i-1][j-1]*max(num[i]-j+1,0)%mo);
    	}
    	Fordown(i,n,k)
    	{
    		ans[i]=1ll*dp[n][i]*mc[n-i]%mo;
    		For(j,i+1,n)add(ans[i],mo-1ll*ans[j]*C[j][i]%mo);
    	}
    	write(ans[k],'
    ');
    }
    int main()
    {
    	file();
    	input();
    	init(max(n,k));
    	work();
    	return 0;
    }
    
    bzoj4361
    • 先设(dp[i][j])表示到第i位,最长不降子序列长为j的方案数,本来是(n^2)的,用(BIT)优化一下
    • (f[i])表示最长非降子序列长为j的方案之和,(f[i]=sum_{j=i}^{n}dp[j][i]*(j-i)!),删去的元素顺序随意
    • 算重,因为有些数列删到(i+1)时就已经满足要求,但我们还是把他删到了(i),所以容斥为(ans=sum_{i=n}^{1}f[i]*(n-i)!-f[i+1]*(n-i-1)!*(i+1)),就是枚举是(i+1)的方案中删掉了哪一个数而非法的
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=2e3+5;
    bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
    bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
    template<typename T>T read()
    {
      T ans=0,f=1;
      char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
      return ans*f;
    }
    template<typename T>void write(T x,char y)
    {
      if(x==0)
      {
          putchar('0');putchar(y);
          return;
      }
      if(x<0)
      {
          putchar('-');
          x=-x;
      }
      static char wr[20];
      int top=0;
      for(;x;x/=10)wr[++top]=x%10+'0';
      while(top)putchar(wr[top--]);
      putchar(y);
    }
    void file()
    {
      #ifndef ONLINE_JUDGE
          freopen("4361.in","r",stdin);
          freopen("4361.out","w",stdout);
      #endif
    }
    int n,a[N];
    void input()
    {
    	n=read<int>();
    	For(i,1,n)a[i]=read<int>();
    }
    const int mo=1e9+7;
    int dp[N][N];
    void add(int &x,int y)
    {
    	x+=y;if(x>=mo)x-=mo;
    }
    struct BIT
    {
    	int sum[N];
    	void update(int x,int v)
    	{
    		for(;x<=n;x+=x&-x)add(sum[x],v);
    	}
    	int cal(int x)
    	{
    		int res=0;
    		for(;x;x-=x&-x)add(res,sum[x]);
    		return res;
    	}
    }s[N];
    int mc[N],ans;
    int f[N],q[N],top;
    void init()
    {
    	For(i,1,n)q[i]=a[i];
    	sort(q+1,q+n+1);
    	top=unique(q+1,q+n+1)-q-1;
    	For(i,1,n)a[i]=lower_bound(q+1,q+top+1,a[i])-q;
    	mc[0]=1;For(i,1,n)mc[i]=1ll*mc[i-1]*i%mo;
    }
    void work()
    {
    	For(i,1,n)
    	{
    		Fordown(j,n,2)
    		{
    			add(dp[i][j],s[j-1].cal(a[i]));
    			s[j].update(a[i],dp[i][j]);
    			add(f[j],dp[i][j]);
    		}
    		dp[i][1]=1;s[1].update(a[i],dp[i][1]);
    		f[1]++;
    	}
    	//For(i,1,n)For(j,1,n)write(dp[i][j],j==n?'
    ':' ');
    	Fordown(i,n,1)
    	{
    		add(ans,1ll*f[i]*mc[n-i]%mo);
    		add(ans,mo-1ll*f[i+1]*mc[n-i-1]%mo*(i+1)%mo);
    	}
    	write(ans,'
    ');
    }
    int main()
    {
    	file();
    	input();
    	init();
    	work();
    	return 0;
    }
    
    bzoj4710
    • 一开始疯狂考虑同一种特产算重的情况,思路完全错误了
    • 因为所有人都要有,所以我们枚举有几个人分到了特产,设(f[i])表示有i个人分到了特产,那么(f[i]=prod_{j=1}^{m}C[a[j]+i-1][i-1]),然后直接二项式容斥就行了
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=1000+5;
    template<typename T>bool cmax(T &a,T b){return (a<b)?a=b,1:0;}
    template<typename T>bool cmin(T &a,T b){return (a>b)?a=b,1:0;}
    template<typename T>T read()
    {
      T ans=0,f=1;
      char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
      return ans*f;
    }
    template<typename T>void write(T x,char y)
    {
      if(x==0)
      {
          putchar('0');putchar(y);
          return;
      }
      if(x<0)
      {
          putchar('-');
          x=-x;
      }
      static char wr[20];
      int top=0;
      for(;x;x/=10)wr[++top]=x%10+'0';
      while(top)putchar(wr[top--]);
      putchar(y);
    }
    void file()
    {
      #ifndef ONLINE_JUDGE
          freopen("4710.in","r",stdin);
          freopen("4710.out","w",stdout);
      #endif
    }
    const int mo=1e9+7;
    int n,m,a[N];
    void input()
    {
    	n=read<int>(),m=read<int>();
    	For(i,1,m)a[i]=read<int>();
    }
    int ans;
    int C[2005][2005];
    const int maxn=2e3;
    void work()
    {
    	For(i,0,maxn)C[i][0]=C[i][i]=1;
    	For(i,2,maxn)For(j,1,i-1)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    	int sum;
    	For(i,1,n)
    	{
    		sum=1;
    		For(j,1,m)sum=1ll*sum*C[a[j]+i-1][i-1]%mo;
    		if((n-i)&1)ans=(ans-1ll*sum*C[n][i]%mo+mo)%mo;
    		else ans=(ans+1ll*sum*C[n][i]%mo)%mo;
    	}
    	write(ans,'
    ');
    }
    int main()
    {
    	file();
    	input();
    	work();
    	return 0;
    }
    
    bzoj
    • (f[i])强制选择i个相同元素的方案数,(f[i]={achoose b}*(2^{2^{n-i}}-1)),注意计算上面指数要(\%(mod-1)),(WA了半天),剩下就是个二项式容斥了
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=1e6+5;
    template<typename T>bool cmax(T &a,T b){return (a<b)?a=b,1:0;}
    template<typename T>bool cmin(T &a,T b){return (a>b)?a=b,1:0;}
    template<typename T>T read()
    {
      T ans=0,f=1;
      char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
      return ans*f;
    }
    template<typename T>void write(T x,char y)
    {
      if(x==0)
      {
          putchar('0');putchar(y);
          return;
      }
      if(x<0)
      {
          putchar('-');
          x=-x;
      }
      static char wr[20];
      int top=0;
      for(;x;x/=10)wr[++top]=x%10+'0';
      while(top)putchar(wr[top--]);
      putchar(y);
    }
    void file()
    {
      #ifndef ONLINE_JUDGE
          freopen("2839.in","r",stdin);
          freopen("2839.out","w",stdout);
      #endif
    }
    const int mo=1e9+7;
    int n,k;
    void input()
    {
    	n=read<int>(),k=read<int>();
    }
    int pw[N],f[N],mc[N],inv[N];
    ll power(ll x,int y)
    {
    	ll res=1;
    	for(;y;x=x*x%mo,y>>=1)if(y&1)res=res*x%mo;
    	return res;
    }
    int C(int n,int m)
    {
    	return 1ll*mc[n]*inv[m]%mo*inv[n-m]%mo;
    }
    void work()
    {
    	pw[0]=1;For(i,1,n)pw[i]=1ll*(pw[i-1]<<1)%mo;
    	For(i,1,n)pw[i]=power(2,pw[i])-1;
    	mc[0]=1;For(i,1,n)mc[i]=1ll*mc[i-1]*i%mo;
    	inv[0]=1;inv[n]=power(mc[n],mo-2);
    	Fordown(i,n-1,1)inv[i]=1ll*inv[i+1]*(i+1)%mo;
    	For(i,k,n)f[i]=1ll*C(n,i)*pw[n-i]%mo;
    	For(i,k+1,n)f[k]=(f[k]+1ll*f[i]*C(i,k)%mo*(((i-k)&1)?-1:1)%mo+mo)%mo;
    	write(f[k],'
    ');
    }
    int main()
    {
    	file();
    	input();
    	work();
    	return 0;
    }
    
    bzoj 4767
    • 首先解个方程,两个解就是两种方式所需要的步数,对于每个障碍点也算出两种方式所需要的步数,然后将解排序,用每个点的方案减去前面所有可以到达它的障碍点到它的方案即可。
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=500+5;
    template<typename T>bool cmax(T &a,T b){return (a<b)?a=b,1:0;}
    template<typename T>bool cmin(T &a,T b){return (a>b)?a=b,1:0;}
    template<typename T>T read()
    {
      T ans=0,f=1;
      char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
      return ans*f;
    }
    template<typename T>void write(T x,char y)
    {
      if(x==0)
      {
          putchar('0');putchar(y);
          return;
      }
      if(x<0)
      {
          putchar('-');
          x=-x;
      }
      static char wr[20];
      int top=0;
      for(;x;x/=10)wr[++top]=x%10+'0';
      while(top)putchar(wr[top--]);
      putchar(y);
    }
    void file()
    {
      #ifndef ONLINE_JUDGE
          freopen("4767.in","r",stdin);
          freopen("4767.out","w",stdout);
      #endif
    }
    int A,B,n;
    int ax,bx,ay,by;
    void input()
    {
    	A=read<int>(),B=read<int>();n=read<int>();
    	ax=read<int>(),ay=read<int>(),bx=read<int>(),by=read<int>();
    }
    void cal(int x1,int y1,int x2,int y2,int &t1,int &t2)
    {
    	int x=x2-x1,y=y2-y1;
    	int temp=x*by-y*bx;
    	int res=by*ax-ay*bx;
    	if(temp%res!=0)t1=t2=-1;
    	else
    	{
    		t1=temp/res;
    		if(bx)
    		{
    			temp=x-ax*t1;
    			if(temp%bx==0)t2=temp/bx;
    			else t1=t2=-1;
    		}
    		else if(by)
    		{
    			temp=y-ay*t1;
    			if(temp%by==0)t2=temp/by;
    			else t1=t2=-1;
    		}
    	}
    }
    const int mo=1e9+7;
    const int maxn=5e5;
    int inv[maxn+5],mc[maxn+5];
    ll power(ll x,int y)
    {
    	ll res=1;
    	for(;y;x=x*x%mo,y>>=1)if(y&1)res=res*x%mo;
    	return res;
    }
    void init()
    {
    	mc[0]=1;For(i,1,maxn)mc[i]=1ll*mc[i-1]*i%mo;
    	inv[0]=1;inv[maxn]=power(mc[maxn],mo-2);
    	Fordown(i,maxn-1,1)inv[i]=1ll*inv[i+1]*(i+1)%mo;
    }
    int C(int x,int y)
    {
    	if(x<y)return 0;
    	return 1ll*mc[x]*inv[y]%mo*inv[x-y]%mo;	
    }
    int ans;
    typedef pair<int,int> pii;
    pii q[N];
    int tot;
    #define mk make_pair
    #define fir first
    #define sec second
    void add(int &a,int b)
    {
    	a+=b;if(a>=mo)a-=mo;
    }
    int path(int i,int j)
    {
    	int x=q[j].fir-q[i].fir	,y=q[j].sec-q[i].sec;
    	if(x<0||y<0)return 0;
    	return C(x+y,y);
    }
    int dp[N];
    void work()
    {
    	int t1,t2;
    	cal(0,0,A,B,t1,t2);
    	if(t1<0||t2<0){puts("0");return;}
    	A=t1,B=t2;
    	q[++tot]=mk(t1,t2);
    	int x,y;
    	For(i,1,n)
    	{
    		x=read<int>(),y=read<int>();
    		cal(0,0,x,y,t1,t2);
    		if(t1>=0&&t2>=0&&t1<=A&&t2<=B)q[++tot]=mk(t1,t2);
    	}
    	sort(q+1,q+tot+1);
    	For(i,1,tot)
    	{
    		dp[i]=C(q[i].fir+q[i].sec,q[i].fir);
    		For(j,1,i-1)add(dp[i],mo-1ll*dp[j]*path(j,i)%mo);
    	}
    	write(dp[tot],'
    ');
    }
    int main()
    {
    	file();
    	input();
    	init();
    	work();
    	return 0;
    }
    
  • 相关阅读:
    灭霸冲刺(7)
    灭霸冲刺(6)
    灭霸冲刺(5)
    灭霸冲刺(4)
    pip安装软件或模块时提示cannot import name 'main'
    mysql的安装与使用
    channels 2.x的使用
    charlesmitmproxyappium的安装与使用
    centos中redis安装
    django+nginx+gunicorn+pipenv微信小程序实践笔记
  • 原文地址:https://www.cnblogs.com/dengyixuan/p/8818624.html
Copyright © 2020-2023  润新知