题目链接

https://loj.ac/problem/2731

题解

首先一个很自然的思路是,设$dp[i][j]$表示选了前$i$列,第$2$行第$i$列的格子是第$j$个被填上的。
还要加个第三维$0/1$,表示第$2$行第$i$列不是/是这一列最后一个被填上的(这决定了它是被上下填上还是被左右填上)。
转移: 若第$2$行第$i$列是棋子,则所有的都转移到$f[i][0][0]$.
(1) $0\rightarrow 0$, 两个互不影响,可以从任意的$j'$的$f[i][j'][0]$转移过来,组合数选出顺序。
(2) $1\rightarrow 0$, $(2,i)\(要在\)(2,i-1)$之前选,可以从大于当前的$j'$转移过来,同样用组合数选出顺序。
(3) $0\rightarrow 1$, $(2,i)\(要在\)(2,i-1)\(之后选。但是这里要求\)(2,i)\(早于\)(1,i)\(和\)(3,i)\(中的至少一个,因此需要分类讨论。我的代码里第一个转移是\)(2,i)\(比上下两个(如果存在)都晚,第二个转移是\)(2,i)$早于上下两个中的一个。

代码

#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
using namespace std; const int N = 2000;
const int P = 1e9+7;
char a[3][N+3];
llong dp[N+3][N*3+3][2];
llong fact[N*3+3],finv[N*3+3];
int n; llong quickpow(llong x,llong y)
{
llong cur = x,ret = 1ll;
for(int i=0; y; i++)
{
if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
cur = cur*cur%P;
}
return ret;
} void updsum(llong &x,llong y) {x = (x+y)%P;} int main()
{
fact[0] = 1ll; for(int i=1; i<=N*3; i++) fact[i] = fact[i-1]*i%P;
finv[N*3] = quickpow(fact[N*3],P-2); for(int i=N*3-1; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;
scanf("%d",&n);
for(int i=0; i<=2; i++) scanf("%s",a[i]+1);
if(a[0][1]=='x'||a[0][n]=='x'||a[2][1]=='x'||a[2][n]=='x') {puts("0"); return 0;}
for(int i=2; i<=n; i++) {if((a[0][i]=='x'&&a[0][i-1]=='x')||(a[2][i]=='x'&&a[2][i-1]=='x')) {puts("0"); return 0;}}
int sum = a[1][1]=='x'?1:0;
dp[1][sum][0] = 1ll;
for(int i=2; i<=n; i++)
{
for(int j=1; j<=sum; j++) {updsum(dp[i-1][j][0],dp[i-1][j-1][0]),updsum(dp[i-1][j][1],dp[i-1][j-1][1]);}
int now = (a[0][i]=='x')+(a[2][i]=='x'); sum += now+(a[1][i]=='x');
if(a[1][i]=='o')
{
dp[i][0][0] = (dp[i-1][sum-now][0]+dp[i-1][sum-now][1])*fact[sum]%P*finv[sum-now]%P;
continue;
}
for(int j=1; j<=sum; j++)
{
if(j-now-1>=0)
{
updsum(dp[i][j][0],(dp[i-1][sum-now-1][1]-dp[i-1][j-now-1][1]+dp[i-1][sum-now-1][0]+P)*fact[j-1]%P*finv[j-now-1]%P);
}
if(now>=1)
{
updsum(dp[i][j][1],dp[i-1][min(j-1,sum-now-1)][0]*fact[sum-j]%P*finv[sum-j-now]);
if(now==2&&j>=2) {updsum(dp[i][j][1],dp[i-1][j-2][0]*(sum-j)%P*(j-1)*2ll%P);}
}
// printf("dp[%d][%d]=(%lld,%lld)\n",i,j,dp[i][j][0],dp[i][j][1]);
}
}
llong ans = 0ll;
for(int i=0; i<=sum; i++) ans = (ans+dp[n][i][0])%P;
printf("%lld\n",ans);
return 0;
}

LOJ #2731 [JOI2016春季合宿]Solitaire (DP、组合计数)的更多相关文章

  1. LOJ #2733 [JOI2016春季合宿]Sandwiches (DP)

    题目链接 https://loj.ac/problem/2733 题解 神仙题-- 首先可以观察到一个结论: 目标块的两块小三明治一定分别是最后和倒数第二个被吃的. 由此我们可以考虑这两块谁先被吃.这 ...

  2. LOJ #2734 Luogu P3615 [JOI2016春季合宿]Toilets (结论、贪心)

    题目链接 (loj) https://loj.ac/problem/2734 (luogu) https://www.luogu.org/problem/P3615 题解 嗯,考场上肝了\(3h\)然 ...

  3. BZOJ 4221 [JOI2012春季合宿]Kangaroo (DP)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4221 题解 orz WYC 爆切神仙DP 首先将所有袋鼠按大小排序.考虑从前往后DP, ...

  4. 3.29省选模拟赛 除法与取模 dp+组合计数

    LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采 ...

  5. JOI2017 春季合宿:Railway Trip

    自己的AC做法似乎离正解偏了十万八千里而且复杂了不少--不管怎样还是记录下来吧. 题意: 题目链接: JOISC2017 F - AtCoder JOISC2017 F - LOJ \(N\)个车站排 ...

  6. UOJ356 [JOI2017春季合宿] Port Facility 【启发式合并】【堆】【并查集】

    题目分析: 好像跑得很快,似乎我是第一个启发式合并的. 把玩具看成区间.首先很显然如果有两个玩具的进出时间有$l1<l2<r1<r2$的关系,那么这两个玩具一定在不同的栈中间. 现在 ...

  7. [JOI2017春季合宿]Port Facility[set、二分图]

    题意 你有两个栈,有 \(n\) 个货物,每个货物有一个进栈时间和出栈时间(所有时间的并集是1~2n),问有多少种不同的入栈方案. \(n\le 10^6\) 分析 把每个货物的存在看成区间,相交的区 ...

  8. UOJ #356. 【JOI2017春季合宿】Port Facility

    Description 小M有两个本质不同的栈. 无聊的小M找来了n个玩具.之后小M把这n个玩具随机顺序加入某一个栈或把他们弹出. 现在小M告诉你每个玩具的入栈和出栈时间,现在她想考考小S,有多少种方 ...

  9. UOJ #357. 【JOI2017春季合宿】Sparklers

    Description 小S和小M去看花火大会. 一共有 n 个人按顺序排成一排,每个人手上有一个仅能被点燃一次的烟花.最开始时第 K 个人手上的烟花是点燃的. 烟花最多能燃烧 T 时间.每当两个人的 ...

随机推荐

  1. Active Learning 主动学习

    Active Learning 主动学习 2015年09月30日 14:49:29 qrlhl 阅读数 21374 文章标签: 算法机器学习 更多 分类专栏: 机器学习   版权声明:本文为博主原创文 ...

  2. Java-this关键词

    this关键词 1,this调用本类属性 在程序里面是有this可以实现以下三类的结构的描述: ·当前类中的属性:this.属性: ·当前类中的方法(普通方法.构造方法):this().this.方法 ...

  3. NET Core:搭建私有Nuget服务器以及打包发布Nuget包

    docker 安装 https://www.cnblogs.com/liuxiaoji/p/11014329.html 1.使用docker搭建私有Nuget服务器 docker run -d -p ...

  4. SpringCloud 配置文件 application.yml和 bootstrap.yml区别

    前言: SpringBoot默认支持properties和YAML两种格式的配置文件.前者格式简单,但是只支持键值对.如果需要表达列表,最好使用YAML格式.SpringBoot支持自动加载约定名称的 ...

  5. 基于光线追踪的渲染中景深(Depth of field)效果的实现

    图形学离线渲染中常用的透视摄像机模型时根据小孔成像的原理建立的,其实现通常是从向成像平面上发射ray,并把trace这条ray的结果作为成像平面上对应交点的采样结果.即: 图片来自<Fundam ...

  6. 4.Struts2-OGNL

    /*ognl 是 strut2 特有的表达式,使用 ognl,struts2 就无需将对象手动放值进request等范围,页面(从值栈中)直接传值*/ OGNL <?xml version=&q ...

  7. C#中构建多线程应用程序[转] ----代码示例

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. SpringBoot-自动配置

    一.自动配置的核心 一般springboot程序,我们都会在主启动类上加上@SpringBootApplication注解,@SpringBootApplication是一个复合注解,上面标注了@Co ...

  9. 华硕B360主板装机找不到固态硬盘启动

      1.开机点按F2进入BIOS中,在security选项卡中选择secure boot menu,secure boot control按Enter选择Disable,按F10保存:   2.电脑重 ...

  10. Linux awk命令 --三剑客老大

    Linux awk命令 --三剑客老大 基本用法: awk  [参数]  ['找谁{干啥}']  文件 参数: -F 分隔符 -v 创建或修改awk变量 OFS 输出分割符 awk显示每一列的时候分隔 ...