zoukankan      html  css  js  c++  java
  • 【题解】方块染色(容斥原理+巧妙分类)

    【题解】方块染色(容斥原理+巧妙分类)

    刚开始以为是道容斥,写了这个错误程序

    
    int main(){
          pre(1e5);
          while(~scanf("%d%d",&n,&m)){
    	    int ans=0;
    	    for(register int t=m,delta;t<=n;++t){
    		  delta=0;
    		  for(register int k=1,d2;k<=n/t;++k){
    			d2=1ll*c(n/t,k)*(n-k*t+1)%mod*bin[n-k*t]%mod;
    			if(k&1) d2=mod-d2;
    			delta+=d2;
    			while(delta>=mod)delta-=mod;
    		  }
    		  if((t-m)&1) delta=mod-delta;
    		  ans=(ans+delta)%mod;
    	    }
    	    printf("%d
    ",ans);
          }
          return 0;
    }
    
    

    这显然是错的,容斥套容斥,我不知道为什么我敢交上去(可能是对了样例)

    后来我通过仔(bai)细(du)思(ti)考(jie)获得了启示

    (dp(n))(n)个时的方案数

    假如我已经知道前面(n-1)的方案,现在要知道(n)的方案了,怎么做?

    显然地,肯定有一个(2dp(n-1))的贡献,意思是在后面加上一个块,什么颜色无所谓

    然后我通过思(ti)考(jie)发现,可以这样分类:

    • 加上去的没有作用,加不加这一块对于满足合法条件没有贡献,直接加就好了,什么颜色无所谓,所以就是(2dp(n-1))

    • 加上去的有作用,那就是说,整个序列只有后缀的(m)个元素有用,其他都是打酱油,那么先钦定后面(m)个都是红色,现在问题就是前面(n-m)个要求不能产生作用,这样才能满足我们这里的分类。

      那么就是总数-不合法呗,但是且慢,假如说我前面(n-m)个和后面这个(m)个连接在一起了,就会和加上去没有作用的那个分类重复。所以我要钦定倒数第(m+1)是蓝色,所以前面总共有(2^{n-m-1}-dp(n-m-1))有贡献了。

      你可能会问,那可能存在一种合法方案,使得是倒数(m+x)个使得整个序列满足条件啊,这种方案去哪了? 这种方案被放在了第一个分类中,因为这样的话,最后一个块什么颜色就无所谓了,少了不会使得整个序列不满足条件。

    所以直接递推:

    [dp(x)=2dp(x-1)+2^{x-m-1}-dp(x-m-1) ]

    初始条件(dp(m)=1)

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(c<48||c>57)f|=c==45,c=getchar();
          while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    const int maxn=1e5+5;
    const int mod=1e9+7;
    int bin[maxn],dp[maxn];
    int n,m;
    
    int main(){
          for(register int t=bin[0]=1;t<=100000;++t){
    	    bin[t]=bin[t-1]<<1;
    	    while(bin[t]>=mod) bin[t]-=mod;
          }
          while(~scanf("%d%d",&n,&m)){
    	    dp[m]=1;
    	    for(register int t=m+1;t<=n;++t){
    		  dp[t]=dp[t-1]<<1;
    		  while(dp[t]>mod) dp[t]-=mod;
    		  dp[t]+=bin[t-m-1];
    		  while(dp[t]>mod) dp[t]-=mod;
    		  if(t-m-1>=m) dp[t]+=mod-dp[t-m-1];
    		  while(dp[t]>mod) dp[t]-=mod;
    	    }
    	    printf("%d
    ",dp[n]);
          }
          return 0;
    }
    
    
    
  • 相关阅读:
    动手动脑篇之类与对象
    团队精神
    在快乐中学习
    实习报告
    大道至简读后感(二)
    大道至简读后感
    读《大道至简》第一章有感
    指令随笔之:tail、cat、scp、&、&&、;、|、>、>>
    NFS安装过程
    CentOS7编译安装Nginx-1.8.1和编译参数
  • 原文地址:https://www.cnblogs.com/winlere/p/11415448.html
Copyright © 2011-2022 走看看