P3266 [JLOI2015]骗我呢

P3266 [JLOI2015]骗我呢

由于\(x_{i,j}<x_{i-1/i,j+1}\),所以我们不难得到每一行元素的一阶差分至多存在一个2,其它则为1

我们称为\(2\)所在的位置为

对于特殊情况,第一个元素为\(1\)时,界为\(0\);不存在两相邻元素差为\(2\)时,界为\(m+1\)

令第\(i\)行界的位置为\(x_i\)

容易发现,\(\forall i\in[1,n),x_i-1\leq x_{i+1}\)

这是一个不经典的模型

考虑转化:从\((0,0)\)走到\((n,m)\),过程中只能走\((1,-1),(0,1),(1,0)\)的每一行被走过的最右的位置构成的序列的方案数

考虑对于第\(i\)行将位置向右平移\(i-1\)再沿\(y=x\)翻折,则问题变成了从\((0,0)\)走到\((n+m-1,n)\),过程中只能走\((1,0),(0,1)\),且不越过\((x-y+1)(x-y-m-2)=0\)的路径数

直接容斥是不易的,考虑从终点开始,不断从两直线进行翻折,容斥(这好像被叫做折线法)

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;
	char k;
	bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
# define ll long long
# define mod 1000000007
int n,m;
ll fac[3000005],inv[3000005];
ll C(int x,int y){return x<y||y<0?0:fac[x]*inv[y]%mod*inv[x-y]%mod;}
void flip1(int &x,int &y){
	swap(x,y);--x;++y;
}void flip2(int &x,int &y){//x=(m+1)+y
	swap(x,y);x+=m+2;y-=m+2;
}
int main(){n=read;m=read;//(n,n+m+1)
	fac[0]=inv[0]=inv[1]=fac[1]=1;
	for(int i=2;i<=n*2+m+1;++i)fac[i]=fac[i-1]*i%mod,inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for(int i=1;i<=n*2+m+1;++i)inv[i]=inv[i-1]*inv[i]%mod;
	ll X=n+m+1,Y=n,ans=C(X+Y,X);
	for(int x=X,y=Y;x>=0&&y>=0;){
		flip1(x,y);ans=(ans-C(x+y,x))%mod;
		flip2(x,y);ans=(ans+C(x+y,x))%mod;
	}for(int x=X,y=Y;x>=0&&y>=0;){
		flip2(x,y);ans=(ans-C(x+y,x))%mod;
		flip1(x,y);ans=(ans+C(x+y,x))%mod;
	}cout<<(ans+mod)%mod;
	return 0;
}
posted @ 2021-08-05 22:27  ファイナル  阅读(58)  评论(0)    收藏  举报