【组合数学+转化问题】BZOJ4005[JLOI2015]骗我呢
2018-02-01 22:37
218 查看
【题目】
原题地址
求有多少个n行m列的矩阵满足每个数都在[0,m]之间且ai,j<ai,j+1,ai,j<ai−1,j+1,答案模1e9+7
【解题思路】
这道题想了我好久啊,然后去看了一下PoPoQQQ的题解,一脸要膜拜的样子。转化后的模型在QBXT讲过qwq。
首先考虑这个矩阵本身有什么性质,发现如果我们将每个大小关系连一条边,那么每个点至少在一条长度为m的链上,而可供选择的数字大小仅有m+1个,也就是说,一条链上最多只有一条边两点权相差为2,其他差值都为1。
考虑转化问题(qwq我不会转化),我们发现实质是是这样一幅图:
求从左下角走到右上角,只能往上或往右走,不碰到两条斜线的方案数。
当然这是n≤m的情况,实际上n>m时也是一样的,我们都构造y=x+1和y=x−(m+2)两条“限制线”即可。
(以下这两条直线称作A和B)
那么接下来考虑如何计算,我们可以尝试用容斥原理,即【全集-跨越第一条的方案-跨越第二条的方案+两条都跨越的方案 】。但是这样最后一种是很难计算的。
下面是另一种转化思路:触碰的情况可能非常复杂 比如ABABBABBBAA啥的,为了避免重复计数我们把相同的都缩掉变成ABABABA这样的串
然后怎么搞呢? 秀操作咯。(接下来的东西我在QBXT是没有认真听的,回来推了好久qwq)
我们令初始点为(n+m+1,n),然后我们做这样的操作:
将当前点沿A翻转,然后把原点到当前点的方案数从答案中减去;
将当前点(注意此时已经翻转过了)沿B翻转,然后把原点到当前点的方案数从答案中加上;
反复如此直到某一坐标<0 此时无论如何进行下去方案数都是0了
这样做相当于把以A和AB为后缀的方案删除,然后把以BA和BAB为后缀的方案加回去,然后把以ABA和ABAB为后缀的方案删除……
最后我删除的就是以A为前缀的所有方案!
然后我们再恢复,先沿B翻转再做一次,就删掉了以B为前缀的所有方案
这样做时间复杂度是O(n)的,写起来也很简单。
还有一种转化方式可以看这里
都好神啊。
【参考程序】
【总结】
事实上我至今仍然觉得转化十分神奇,虽然是已经大概搞懂了。
这也说明数学方面的思维还有待提高,和一众神犇的差距还很大qwq。
原题地址
求有多少个n行m列的矩阵满足每个数都在[0,m]之间且ai,j<ai,j+1,ai,j<ai−1,j+1,答案模1e9+7
【解题思路】
这道题想了我好久啊,然后去看了一下PoPoQQQ的题解,一脸要膜拜的样子。转化后的模型在QBXT讲过qwq。
首先考虑这个矩阵本身有什么性质,发现如果我们将每个大小关系连一条边,那么每个点至少在一条长度为m的链上,而可供选择的数字大小仅有m+1个,也就是说,一条链上最多只有一条边两点权相差为2,其他差值都为1。
考虑转化问题(qwq我不会转化),我们发现实质是是这样一幅图:
求从左下角走到右上角,只能往上或往右走,不碰到两条斜线的方案数。
当然这是n≤m的情况,实际上n>m时也是一样的,我们都构造y=x+1和y=x−(m+2)两条“限制线”即可。
(以下这两条直线称作A和B)
那么接下来考虑如何计算,我们可以尝试用容斥原理,即【全集-跨越第一条的方案-跨越第二条的方案+两条都跨越的方案 】。但是这样最后一种是很难计算的。
下面是另一种转化思路:触碰的情况可能非常复杂 比如ABABBABBBAA啥的,为了避免重复计数我们把相同的都缩掉变成ABABABA这样的串
然后怎么搞呢? 秀操作咯。(接下来的东西我在QBXT是没有认真听的,回来推了好久qwq)
我们令初始点为(n+m+1,n),然后我们做这样的操作:
将当前点沿A翻转,然后把原点到当前点的方案数从答案中减去;
将当前点(注意此时已经翻转过了)沿B翻转,然后把原点到当前点的方案数从答案中加上;
反复如此直到某一坐标<0 此时无论如何进行下去方案数都是0了
这样做相当于把以A和AB为后缀的方案删除,然后把以BA和BAB为后缀的方案加回去,然后把以ABA和ABAB为后缀的方案删除……
最后我删除的就是以A为前缀的所有方案!
然后我们再恢复,先沿B翻转再做一次,就删掉了以B为前缀的所有方案
这样做时间复杂度是O(n)的,写起来也很简单。
还有一种转化方式可以看这里
都好神啊。
【参考程序】
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int mod=1e9+7; const int N=3e6+10; int n,m,x,y,ans; int fac ,inv ; void init() { fac[0]=fac[1]=1; for(int i=2;i<N;++i) fac[i]=1ll*fac[i-1]*i%mod; inv[0]=inv[1]=1; for(int i=2;i<N;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; for(int i=2;i<N;++i) inv[i]=1ll*inv[i]*inv[i-1]%mod; } int C(int p,int q) { if(p<q) return 0; return 1ll*fac[p]*inv[q]%mod*inv[p-q]%mod; } int calc(int p,int q) { if(p<0 || q<0) return 0; return C(p+q,p); } void flip1(int &p,int &q)//flip by y=x+1 { swap(p,q); --p;++q; } void flip2(int &p,int &q)//flip by y=x-(m+2) { swap(p,q); p+=m+2;q-=m+2; } void solve() { scanf("%d%d",&n,&m); ans=calc(n+m+1,n); x=n+m+1;y=n; while(x>=0 && y>=0) { flip1(x,y); ans-=calc(x,y); flip2(x,y); ans+=calc(x,y); ans%=mod; } x=n+m+1;y=n; while(x>=0 && y>=0) { flip2(x,y); ans-=calc(x,y); flip1(x,y); ans+=calc(x,y); ans%=mod; } ans=(ans+mod)%mod; printf("%d\n",ans); } int main() { // freopen("BZOJ4005.in","r",stdin); // freopen("BZOJ4005.out","w",stdout); init(); solve(); return 0; }
【总结】
事实上我至今仍然觉得转化十分神奇,虽然是已经大概搞懂了。
这也说明数学方面的思维还有待提高,和一众神犇的差距还很大qwq。
相关文章推荐
- bzoj 4487: [Jsoi2015]染色问题 组合数学+容斥原理
- 【bzoj3997】[TJOI2015]组合数学 dp
- Topcoder SRM661 ColorfulLineGraphs,数学组合问题+快速幂求解
- 两人取石子游戏 组合数学-博弈问题
- BZOJ 3997 [TJOI2015]组合数学(单调DP)
- BZOJ 3997: [TJOI2015]组合数学
- bzoj 3997 [TJOI2015]组合数学(DP)
- 【阅读具体数学笔记】递归分类下的约瑟夫问题将递归式转化为封闭式
- [数学]组合问题
- CodeForces 233B Non-square Equation(数学问题方程转化)
- ACM学习历程—SNNUOJ 1116 A Simple Problem(递推 && 逆元 && 组合数学 && 快速幂)(2015陕西省大学生程序设计竞赛K题)
- C/C++面试之算法系列--如何利用数学思想解1/2/5组合问题
- 问题 A : 人生三大幻觉(组合数学)
- 组合数学 - 母函数 + 模板题 : 整数拆分问题
- 3997: [TJOI2015]组合数学
- bzoj3997 [TJOI2015]组合数学
- 球和盒子的组合数学问题
- 两人取石子游戏 组合数学-博弈问题
- 2015深圳杯数学建模-DNA序列k-mer index问题
- 【HDU5545 2015 CCPC 南阳国赛F】【差分约束思想 费用流思想】The Battle of Guandu 官渡之战 重要战场人数多 士兵流向转化问题为最短路spfa+dijkstra双写