• 【洛谷3266】[JLOI2015] 骗我呢(坐标系走路神仙题)


    点此看题面

    • 有一张(n imes m)的网格图,每个位置只能填入([0,m])
    • 要求满足每个位置((i,j))((i,j+1))((i-1,j+1))都小,求方案数。
    • (n,mle10^6)

    动态规划

    首先发现总共只有(m+1)种数,而每一行都要填(m)个递增的数,因此一行的状态实际上只需要考虑哪个数没有即可。

    即,设(f_{i,j})表示第(i)行没有的数是(j)的方案数。

    考虑转移,画画图发现(kle j+1)(f_{i-1,k})都是可以转移的,而更大的(k)就不满足条件了。

    因此得出转移方程:

    [f_{i,j}=sum_{k=0}^{j+1}f_{i-1,k}=f_{i,j-1}+f_{i-1,j+1} ]

    坐标系走路的转化

    把转移表示到图上去:(图画得很丑,但我尽力了。。。)

    发现斜着的转移很难表示,所以我们先把它掰直,变成:

    那么也就相当于我们不能触碰到下图中的两条蓝线(A)(B)

    容斥

    (画不动图了,而且估计我画得这么丑也没人看,因此就不放了)

    经典容斥问题。

    以第一条线(A)为例,我们找到终点关于它的对称点,那么抵达对称点的方案等同于以(A)结尾或以(AB)结尾的非法路径。同理以(B)为例,抵达关于它的对称点的方案等同于以(B)结尾或以(BA)结尾的非法路径。

    但它们之间的非法路径肯定存在包含关系,因为以(A)结尾也就包含了以(BA)结尾,因此需要容斥。

    具体地,依旧以第一条线(A)为例,我们找到终点关于它的对称点,用答案减去这一部分方案数,然后找到这个对称点关于第二条线(B)的对称点,给答案加上这一部分方案数,然后再回去给当前对称点找到第一条线的对称点减去方案数,以此类推,直至越界(某一维小于(0))。第二条线则反之。

    显然终点坐标为((n+m+1,n))。而关于对称点,有解析式(A:y=x+1,B:y=x-m-2),所以((x,y))关于(a,b)的对称点分别为((y-1,x+1),(y+m+2,x-m-2))

    代码实现很简单,但思维难度真的高。

    代码:(O(n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define X 1000000007
    using namespace std;
    int n,m;I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    int Fac[3*N+5],IFac[3*N+5];I void InitFac(CI S)
    {
    	RI i;for(Fac[0]=i=1;i<=S;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理阶乘
    	for(IFac[i=S]=QP(Fac[S],X-2);i;--i) IFac[i-1]=1LL*IFac[i]*i%X;//预处理阶乘逆元
    }
    I void A(int& x,int& y) {RI a=y-1,b=x+1;x=a,y=b;}//把点按A翻转
    I void B(int& x,int& y) {RI a=y+m+2,b=x-m-2;x=a,y=b;}//把点按B翻转
    int main()
    {
    	#define Calc(x,y) ((x)>=0&&(y)>=0?1LL*Fac[(x)+(y)]*IFac[x]%X*IFac[y]%X:0)//到达(x,y)的方案数,就是C(x+y,x)
    	scanf("%d%d",&n,&m),InitFac(3*max(n,m)+1);RI x,y,t=Calc(n+m+1,n);
    	x=n+m+1,y=n;W(x>=0&&y>=0) A(x,y),t=(t-Calc(x,y)+X)%X,x>=0&&y>=0&&(B(x,y),t=(t+Calc(x,y))%X);//对于A的容斥
    	x=n+m+1,y=n;W(x>=0&&y>=0) B(x,y),t=(t-Calc(x,y)+X)%X,x>=0&&y>=0&&(A(x,y),t=(t+Calc(x,y))%X);//对于B的容斥
    	return printf("%d
    ",t),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    PDF上添加水印
    java调用POI读取Excel
    搭建Linux的VMware Workstation Pro
    js中两种定时器的设置及清除
    SUI使用经验
    List集合与Array数组之间的互相转换
    jquery操作select
    jquery操作CheckBox
    时间格式
    java 获取路径的各种方法
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3266.html
Copyright © 2020-2023  润新知