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

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

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


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\n",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\n",dp[n]);
      }
      return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/11415448.html

时间: 2024-07-30 15:49:22

【题解】方块染色(容斥原理+巧妙分类)的相关文章

[HAOI2018][bzoj5306] 染色 [容斥原理+NTT]

广告 蒟蒻のblog 思路 这道题的核心在于"恰好有\(k\)种颜色占了恰好\(s\)个格子" 这些"恰好",引导我们去思考,怎么求出总的方案数呢? 分开考虑 考虑把恰好有\(s\)个格子的颜色,和不是\(s\)个颜色的格子分开来考虑 那么,显然答案可以用这样的一个式子表示: 令\(lim=min(\lfloor\frac ns\rfloor,m)\),那么: \(ans=\sum_{i=0}^{lim}w_iC_m^iC_n^{is}\frac{(is)!}{(s

【bzoj1042】[HAOI2008]硬币购物 背包dp+容斥原理

题目描述 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. 输入 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000 输出 每次的方法数 样例输入 1 2 5 10 2 3 2 3 1 10 1000 2 2 2 900 样例输出 4 27 题解 背包dp+容斥原理 考虑没有硬币个数限制,那么本题显然是完全

【题解】51nod1327 棋盘游戏

那天和机房的同学们一起想了很久,然而并没有做出来……今天看了题解,的确比较巧妙,不过细细想来其实规律还是比较明显,在这里记录一下~ 当天自己做的时候,主要想到的是两点 : 1.按列dp 2.对行进行排序.虽然没有做出来,但做法的确和这两点是重合的.我们考虑强制满足左端点,然后 dp 右端点的方法,记录状态 \(f[i][j][k]\) 为 dp 到第 \(i\) 列时,有 \(j\) 列是空的,且还有 \(k\) 个右端点没有满足(这 \(k\) 个右端点的位置均 \(<= i\)). 首先从

「总结」容斥原理

容斥原理. 最近被容斥虐惨了,要总结一下知识点和写一些题解. 1.容斥原理 首先是很熟悉的奇加偶减的式子. 令$M$为$A$的集合. $$\left|\bigcup\limits_{i=1}^{n}S_i\right|=\sum\limits_{C\subseteq M}^{n}(-1)^{size(C)-1}\left|\bigcap\limits_{T\subseteq C}T\right|$$ 这个式子就是最重要的了. 所有的反演以及容斥系数的确定,原理都是他.这也是容斥原理是原理的原因.

【poj3734】矩阵乘法求解

[题意] 给N个方块排成一列.现在要用红.蓝.绿.黄四种颜色的油漆给这些方块染色.求染成红色方块和染成绿色方块的个数同时为偶数的染色方案的个数,输出对10007取余后的答案.(1<=n<=10^9). [分析] 看到这题的题目的第一想法是什么呢?我也不知道,因为还没做就知道是一道用矩阵乘法完成递推的题目了嘛!! 之前对矩阵乘法的理解不是很好,不知道可以同时推很多个元素的,于是脑子就卡了~~不写那么多乱七八糟的想法了,直接写题解吧. 当我们准备准备染第i个方块的时候,前i-1个方块已经染好颜色了

【LeetCode】哈希表 hash_table(共88题)

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica } [1]Two Sum (2018年11月9日,k-sum专题,算法群衍生题) 给了一个数组 nums, 和一个 target 数字,要求返回一个下标的 pair, 使得这两个元素相加等于 target . 题解:我这次最大范围的优化代码, hash-table + one pass,时间复杂度 O(N),空间复杂度 O(N).重点在于动态找,一边生成hash-tabl

POJ4007 Flood-it!

Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 337   Accepted: 123 Description Flood-it is a fascinating puzzle game on Google+ platform. The game interface is like follows: At the beginning of the game, system will randomly generate an

BZOJ1055: [HAOI2008]玩具取名

1055: [HAOI2008]玩具取名 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 820  Solved: 482[Submit][Status] Description 某人有一套玩具,并想法给玩具命名.首先他选择WING四个字母中的任意一个字母作为玩具的基本名字.然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长.现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的

POJ1067 取石子游戏

Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后把石子全部取完者为胜者.现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者. Input 输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000. Output 输出对应也有