【SDOI2019】染色(DP)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zxyoi_dreamer/article/details/102731269

传送门


题解:

首先我们可以设置DP状态为 f i , x , y f_{i,x,y} 表示当前DP到第 i i 列,两个格子的颜色分别为 x , y x,y 的方案数。显然我们需要优化。

考虑想办法快速跳过中间两个位置都空的格子。

考虑枚举起始列和终止列的状态,然后考虑中间的空格子的方案数,注意我们这里是在假设两边都已经确定了的情况下进行计数。

本质不同的情况有5种(其中不同字母表示的颜色不同):

  1. ( x x y y ) \begin{pmatrix}x\cdots x\\y\cdots y\end{pmatrix}
  2. ( x y y x ) \begin{pmatrix}x\cdots y\\y\cdots x\end{pmatrix}
  3. ( x x y w ) \begin{pmatrix}x\cdots x\\y\cdots w\end{pmatrix} 等价于 ( x w y y ) \begin{pmatrix}x\cdots w\\y\cdots y\end{pmatrix}
  4. ( x w y x ) \begin{pmatrix}x\cdots w\\y\cdots x\end{pmatrix} 等价于 ( x y y w ) \begin{pmatrix}x\cdots y\\y\cdots w\end{pmatrix}
  5. ( x u y v ) \begin{pmatrix}x\cdots u\\y\cdots v\end{pmatrix}

处理出 g [ l ] [ 0 / 1 / 2 / 3 / 4 ] g[l][0/1/2/3/4] 表示中间空列数量为 l 1 l-1 的时候两种状态之间的转移系数。

处理 g g 也是考虑DP,注意这里只算考虑中间空列的填空数量,所以对于 3 , 4 , 5 3,4,5 三种情况我们需要修正,同时 3 , 4 3,4 是包含了两种状态的,需要在转移中体现出来,具体可以看代码。

有的列是两个格子填满了的,显然以这些列为分界线两边的格子互不干扰,于是我们把这些区间各自的答案算出来就行了。

发现转移可以用D1T1的东西优化,然后就没了。


代码(由于我看的是zsy神仙的题解,代码基本上就是按照zsy的思路写的):

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int mod=1e9+9;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b){
	int r=1;for(;b;b>>=1,a=mul(a,a))
	(b&1)&&(r=mul(r,a));return r;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline void ex_gcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return ;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}
inline int inv(int a){
	int x,y;ex_gcd(mod,a,y,x);
	return x+(x>>31&mod);
}

cs int N=1e5+7;
int n,m,k,ans=1;
int a[N],b[N],c[N],p[N],g[N][5];

inline void init_g(){
	int coef[5][5]={
		{0,1,0,m-2,mul(m-2,m-3)},
		{1,0,m-2,0,mul(m-2,m-3)},
		{0,2,m-2,2*m-5,mul(2,mul(m-3,m-3))},
		{2,0,2*m-5,m-2,mul(2,mul(m-3,m-3))},
		{1,1,m-3,m-3,mul(m-3,m-4)+1}
	};g[0][0]=1;
	for(int re i=1;i<=n;++i)
	for(int re j=0;j<5;++j)if(g[i-1][j])
	for(int re k=0;k<5;++k)Inc(g[i][k],mul(g[i-1][j],coef[j][k]));
	int v1=inv(m-2),v2=inv(mul(m-2,m-3));
	for(int re i=1;i<=n;++i){
		Mul(g[i][2],v1);
		Mul(g[i][3],v1);
		Mul(g[i][4],v2);
	}
}

inline int cal(int x,int y,int l,int u,int v){
	if(x==u)return y==v?g[l][0]:g[l][2];
	if(x==v)return y==u?g[l][1]:g[l][3];
	if(y==u)return g[l][3];
	if(y==v)return g[l][2];
	return g[l][4];
}

struct array{
	int f[N],tag_mul,inv_mul,tag_add,sum,st[N<<2|7],tp;
	array(){tag_mul=inv_mul=1;}
	inline int get(int x){return add(mul(f[x],tag_mul),tag_add);}
	inline int query(){return sum;}
	inline void set(int x,int y){
		Dec(sum,get(x));Inc(sum,y);st[++tp]=x;
		f[x]=mul(inv_mul,dec(y,tag_add));
	}
	inline void cov(int a){
		while(tp)f[st[tp--]]=0;
		sum=mul(a,m);tag_mul=inv_mul=1,tag_add=a;
	}
	inline void plus(int a){
		Inc(sum,mul(a,m));
		Inc(tag_add,a);
	}
	inline void mult(int a){
		if(!a)return cov(0);
		Mul(sum,a);Mul(tag_mul,a);
		Mul(tag_add,a),Mul(inv_mul,inv(a));
	}
}F;

inline void start(int x,int y,int l,int w){
	if(w==x)
		F.cov(g[l][2]),F.set(x,0),F.set(y,g[l][0]);
	else if(w==y)
		F.cov(g[l][3]),F.set(x,g[l][1]),F.set(y,0);
	else
		F.cov(g[l][4]),F.set(x,g[l][3]),F.set(y,g[l][2]),F.set(w,0);
}

inline void trans(int x,int y,int l,int w){
	if(x==y){
		int fs=F.query();
		F.mult(dec(g[l][0^w],g[l][2^w]));
		F.plus(mul(fs,g[l][2^w]));
		F.set(x,0);
	}else {
		int fy=F.get(y),fs=dec(F.query(),fy);
		F.mult(dec(g[l][2^w],g[l][4]));
		F.plus(add(mul(g[l][4],fs),mul(g[l][3^w],fy)));
		F.set(x,add(mul(g[l][3^w],fs),mul(g[l][1^w],fy)));
		F.set(y,0);
	}
}

inline void finish(int x,int y,int l,int w){
	int res=0;
	if(w==x){
		int fy=F.get(y),fs=dec(F.query(),fy);
		res=add(mul(fy,g[l][0]),mul(fs,g[l][2]));
	}else if(w==y){
		int fx=F.get(x),fs=dec(F.query(),fx);
		res=add(mul(fx,g[l][1]),mul(fs,g[l][3]));
	}else {
		int fx=F.get(x),fy=F.get(y),fs=dec(F.query(),add(fx,fy));
		res=add(mul(fs,g[l][4]),add(mul(fx,g[l][3]),mul(fy,g[l][2])));
	}
	Mul(ans,res);
}

signed main(){
#ifdef zxyoi
	freopen("dye.in","r",stdin);
#endif
	n=gi(),m=gi();init_g();
	for(int re i=1;i<=n;++i)a[i]=gi();
	for(int re i=1;i<=n;++i)b[i]=gi();
	for(int re i=1;i<=n;++i)if(a[i]||b[i]){
		p[++k]=i;a[k]=a[i],b[k]=b[i];
		if(b[k]){
			if(!a[k])std::swap(a[k],b[k]),c[k]=1;
			else {
				if(a[k]==b[k])return puts("0"),0;
				c[k]=2;
			}
		}
	}
	int pw=power(mul(m-1,m-2)+1,p[1]-1);
	if(c[1]<2)F.cov(pw),F.set(a[1],0);
	else ans=pw;
	for(int re i=2;i<=k;++i){
		if(c[i-1]==2){
			if(c[i]==2)Mul(ans,cal(a[i-1],b[i-1],p[i]-p[i-1],a[i],b[i]));
			else {
				if(c[i])std::swap(a[i-1],b[i-1]);
				start(a[i-1],b[i-1],p[i]-p[i-1],a[i]);
				if(c[i])std::swap(a[i-1],b[i-1]);
			}
		}else {
			if(c[i]==2){
				if(c[i-1])std::swap(a[i],b[i]);
				finish(a[i],b[i],p[i]-p[i-1],a[i-1]);
				if(c[i-1])std::swap(a[i],b[i]);
			}else trans(a[i-1],a[i],p[i]-p[i-1],c[i]^c[i-1]);
		}
	}
	if(c[k]<2)Mul(ans,F.query());
	Mul(ans,power(mul(m-1,m-2)+1,n-p[k]));
	cout<<ans<<"\n";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/102731269