【题解】At2370 Piling Up

\[dp(i,j,0/1)
\\
正在进行i项操作并且此时黑球剩下j个,黑球[0/1]数量曾经到过0
\\
为什么加第二位,判重。怎么想到的?
\]

非常神仙了。现在我做题基本上就是改编戏说了...自己是做不出来的,不管是只是层面还是思维层面的高度都不够。

那就一题一题地吸收吧。

其实问这样的\(dp\)设计是如何想到的,都是人们看清楚了方案重合的本【题解】At2370 Piling Up质是什么,然后就针对这个本质设计来的...

感觉这种设\(0/1\)有一定的代表性,图文解释一下



假设蓝色的线是黑球的数量关于\(t\)的变化关系函数,可以知道同样形状的线拿出来的样子是一样的,但是如果直接\(dp(i,j)\)没有\(0\ / \ 1\)就会把图中四根线代表的颜色序列当做不一样的,这样就重复了。

有什么办法可以避免呢?我们可以发现,同样的走的曲线一定是将整个坐标系排满了,意思是排到无法再加入新的同样走的曲线进去了,如果要无法再加曲线,那么一定有一根曲线曾经到过坐标轴(黑线)。这是解决重复的关键,也是问题的本质。

也就是说,我们标识一个\(dp(i,j)\)是否曾经到过底部,就可以防止这样的重复了。

你肯定发现问题了,一定存在这样的排颜色方案使得黑球数量从没有为0。不过我们钦定一条在\(i=0\)处变为\(0\)的曲线就好了。



考虑怎么转移,分类讨论:

  • 白白
  • 黑黑
  • 白黑
  • 黑白

转移很好转移(也没有好吗!这种转移对我来说就相当于做第二道题目了!就是那种神仙学长都觉得很显然但是我要折寿地去推导啊啊啊啊啊啊啊QAQQAQ)。

上抄的代码,wk1自己写的(不对),wk2是题解

#include<bits/stdc++.h>

using namespace std;typedef long long ll;
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;++t)
#define ERP(t,a) for(register int t=head[a];t;t=e[t].nx)
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
#define pushup(pos) (seg[pos]=seg[pos<<1]+seg[pos<<1|1])
TMP inline ccf qr(ccf b){
register char c=getchar();register int q=1;register ccf x=0;
while(c<48||c>57)q=c==45?-1:q,c=getchar();
while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
return q==-1?-x:x;}
TMP inline ccf Max(ccf a,ccf b){return a<b?b:a;}
TMP inline ccf Min(ccf a,ccf b){return a<b?a:b;}
TMP inline ccf Max(ccf a,ccf b,ccf c){return Max(a,Max(b,c));}
TMP inline ccf Min(ccf a,ccf b,ccf c){return Min(a,Min(b,c));}
TMP inline ccf READ(ccf* _arr,int _n){RP(t,1,_n)_arr[t]=qr((ccf)1);}
//----------------------template&IO---------------------------
const int maxn=3e3+15;
const ll mod=1e9+7;
ll dp[maxn][maxn][2];
ll ans;
#define md(x) ((x)%mod)
#define add(x,y) ((x)=md((x)+(y))) int n,m;
inline void wk(){
dp[1][0][1]=dp[1][1][1]=1;
RP(t,1,n) dp[1][t][0]=2;
RP(t,1,m){
RP(i,0,n){
//取两个白
if(i<n){
if(i){
dp[t+1][i+1][0]=md(dp[t+1][i+1][0]+dp[t][i][0]);
dp[t+1][i+1][1]=md(dp[t+1][i+1][1]+dp[t][i][1]);
}
else dp[t+1][i+1][1]=md(dp[t+1][i+1][1]+dp[t][i][0]+dp[t][i][1]);
}
//取两个黑色
if(i){
if(i-1){
dp[t+1][i-1][0]=md(dp[t+1][i-1][0]+dp[t][i][0]);
dp[t+1][i-1][1]=md(dp[t+1][i-1][1]+dp[t][i][1]);
}
else dp[t+1][i-1][1]=md(dp[t+1][i-1][1]+dp[t][i][0]+dp[t][i][1]);
}
//一黑一白
if(i){
dp[t+1][i][0]=md(dp[t+1][i][0]+(dp[t][i][0]<<1));
dp[t+1][i][1]=md(dp[t+1][i][1]+(dp[t][i][1]<<1));
}
else dp[t+1][i][1]=md(dp[t+1][i][1]+dp[t][i][0]);
}
}
} inline void wk2(){ dp[1][0][1]=1;
RP(t,1,n) dp[1][t][0]=1;
RP(t,1,m){
RP(i,0,n){
if(i){
add(dp[t+1][i-1][1],dp[t][i][1]);
add(dp[t+1][i][1],dp[t][i][1]);
if(i==1) add(dp[t+1][i-1][1],dp[t][i][0]),add(dp[t+1][i][1],dp[t][i][0]);
else add(dp[t+1][i-1][0],dp[t][i][0]),add(dp[t+1][i][0],dp[t][i][0]); }
if(i<n){
add(dp[t+1][i+1][0],dp[t][i][0]);
add(dp[t+1][i+1][1],dp[t][i][1]); add(dp[t+1][i][0],dp[t][i][0]);
add(dp[t+1][i][1],dp[t][i][1]);
}
}
}
} int main(){ n=qr(1);m=qr(1);
wk2();
RP(t,0,n) ans=md(ans+dp[m+1][t][1]);
cout<<ans<<endl;
return 0;
}

【题解】At2370 Piling Up的更多相关文章

  1. AT2370 Piling Up

    https://www.luogu.org/jump/atcoder/2370 题解 答案不是\(2^{2m}\)因为每轮的第一次取球可能会不够. 我们可以设\(dp[i][j]\)表示到了第\(i\ ...

  2. 【题解】Counting D-sets(容斥+欧拉定理)

    [题解]Counting D-sets(容斥+欧拉定理) 没时间写先咕咕咕. vjCodeChef - CNTDSETS 就是容斥,只是难了一二三四五\(\dots \inf\)点 题目大意: 给定你 ...

  3. 一句话题解&&总结

    CF79D Password: 差分.两点取反,本质是匹配!最短路+状压DP 取反是套路,匹配是发现可以把操作进行目的化和阶段化,从而第二次转化问题. 且匹配不会影响别的位置答案 sequence 计 ...

  4. AtCoder Grand Contest 013D: Piling Up 题解

    题意简化: [luogu] Piling Up 一开始有n个颜色为黑白的球,但不知道黑白色分别有多少,m次操作,每次先拿出一个球,再放入黑白球各一个,再拿出一个球,最后拿出的球按顺序排列会形成一个颜色 ...

  5. 【agc013d】Piling Up(动态规划)

    [agc013d]Piling Up(动态规划) 题面 atcoder 洛谷 有\(n\)个球,颜色为黑白中的一种,初始时颜色任意. 进行\(m\)次操作,每次操作都是先拿出一个求,再放进黑白各一个, ...

  6. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  7. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  8. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  9. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

随机推荐

  1. WinSCP介绍、安装、使用(转)

    http://blog.csdn.net/liang19890820/article/details/49700931 前言 如果说XManager通过Xshell.Xftp可以很方便的进行远程管理, ...

  2. delphi如何把一个整数转化为4个十六进制字节

    var   s:string;   len:Integer;   AData:TBytes; begin        s:=IntToHex(149259,6);//返回6位字符串     len  ...

  3. JavaScript中的普通函数和箭头函数

    最近被问到了一个问题: javaScript 中的箭头函数 ( => ) 和普通函数 ( function ) 有什么区别? 我当时想的就是:这个问题很简单啊~(flag),然后做出了错误的回答 ...

  4. [置顶] django快速获取项目所有的URL

    django快速获取项目所有的URL django1.10快速获取项目所有的URL列表,可以用于权限控制 函数如下: import re def get_url(urllist , parent='' ...

  5. 代码篇之AOP框架

    AopFrameworkTest类 public class AopFrameworkTest { public static void main(String[] args) throws Exce ...

  6. 关于js对象的基础使用方法-《javascript设计模式》读书笔记

    一.利用对象收编变量 当我们决定实现某一项功能的时候最简单的其实就是写一个命名函数,然后调用来实现,就像这样: function checkName(){ //验证姓名 } function chec ...

  7. 2016.11.25 activiti的配置文件解析

    参考来自activiti的用户手册.   activiti的配置文件解析 1.processEngine的配置 注意,单独创建流程引擎与spring方式创建流程引擎是不一样的,区别在于:process ...

  8. 线程间操作无效: 从不是创建控件“XXX”的线程访问它

    方法1 Invoke((MethodInvoker)(()=>{XXX.Text = message;})); 方法2 取消跨线程检查 Control.CheckForIllegalCrossT ...

  9. mysql left join中on后加条件判断和where中加条件的区别

    left join中关于where和on条件的几个知识点: .多表left join是会生成一张临时表,并返回给用户 .where条件是针对最后生成的这张临时表进行过滤,过滤掉不符合where条件的记 ...

  10. Java集合框架GS Collections具体解释

    Java集合框架GS Collections具体解释 作者:chszs.未经博主同意不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs GS Collec ...