【题解】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. 2016北京集训测试赛(十七)Problem A: crash的游戏

    Solution 相当于要你计算这样一个式子: \[ \sum_{x = 0}^m \left( \begin{array}{} m \\ x \end{array} \right) \left( \ ...

  2. WPF 自动验证

    WPF中TextBox的自动验证: 演示 : 用以下两个TextBox分别显示验证IP和非空值验证,先看效果: IP自动验证效果: 非空值自动验证效果: 第一步:定义TextBox验证的样式: < ...

  3. RequireJS解决代码依赖问题,异步加载js,避免页面失去相应

    RequireJS的目标是鼓励代码的模块化,它使用了不同于传统<script>标签的脚本加载步骤.可以用它来加速.优化代码,但其主要目的还是为了代码的模块化.它鼓励在使用脚本时以modul ...

  4. C# 导出 数据 到Excel

    /// <summary> /// 实现将数据导出至Excel, /// 在上面的代码中,我们首先将gridview绑定到指定的数据源中,然后在button1的按钮(用来做导出到EXCEL ...

  5. Android 蓝牙技术 实现终端间数据传输

    蓝牙技术在智能硬件方面有很多用武之地,今天我就为大家分享一下蓝牙技术在Android系统下的使用方法技巧.蓝牙是一种短距离的无线通信技术标准,蓝牙协议分为4层,即核心协议层.电缆替代协议层.电话控制协 ...

  6. sudo如何保持当前用户的环境变量?

    现象,我在/etc/profile里设置全局代理,然后使用命令 1.curl http://www.baidu.com  走代理 2.sudo curl http://www.baidu.com 并没 ...

  7. EasyMvc入门教程-基本控件说明(13)选项卡导航

    选项卡Tab导航主要用于企业页面显示不同子类或者子页面的信息内容. 先来一个基本的使用例子:代码如下: @{ var data = new List<TabItem>() { new Ta ...

  8. JAVA使用外部字体将文字生成图片,并使用FontMetrics居中文字

    需求: 1.用户输入文字,根据外部字体,将文字生成图片 2.输出的文字需要居中在图片中显示 遇到的问题: 1.如何导入外部字体?使用Java的Font类,所有的字体都是系统安装过的 2.每次用户输入的 ...

  9. JavaScript中给二维数组动态添加元素的质朴方法

    var myData = new Array(); for(var i=0;i<tableDatas.length;i++){ var arr=tableDatas[i]; ...... /// ...

  10. 【设计模式】工厂方法(FactoryMethod)模式

    看不见PPT的请自行解决DNS污染问题. 相关类的代码: namespace FactoryPatternConsole.Model { public class Address { public s ...