Portal
妙哉
我也不知道题解是怎么想出来的。
先考虑只看有数的两列,会发现,转移只有其中情况:
其中xy不与wz不同。中间就全是0.
这个东西也是可以Dp出来的,第2和第3种情况是类似的,方案数是一样的,第4和第5种的情况也是类似的。
然后我们单独提出来就好了。
用表示第i列,空余那位为j的方案数,空余是什么意思呢?
首先全0的就不用考虑了,只有一个0的话,空余那位记录的就是那一个0取j的方案数。
如果没有空余,若为,认为只有有值就可以了。对于
转移具体可以看看代码,主要是分两列数是否全有值来维护。
线段树优化不怎么懂,在这里暂时留个坑。
#include
using namespace std;
const int N=100010;
int n,C,op,data;
long long dp[2][N],sum[2];
long long g[N][5];
int A[N],B[N];
const long long mod=1e9+9;
long long ksm(long long x,long long t){
long long tot=1;
while(t){
if(t&1) (tot*=x)%=mod;
(x*=x)%=mod;
t/=2;
}
return tot;
}
void prepare(){
g[0][1]=g[0][3]=g[0][4]=1;
long long d=1ll*(C-2)*(C-3)%mod,dd=2*(C-2);
for(int i=1;i<=n;i++){
g[i][0]=(g[i-1][1]+g[i-1][3]*dd%mod+g[i-1][4]*d%mod)%mod;
g[i][1]=(g[i-1][0]+g[i-1][2]*dd%mod+g[i-1][4]*d%mod)%mod;
g[i][2]=(g[i-1][1]+g[i-1][3]*(dd-1)%mod+g[i-1][2]*(C-2)%mod+g[i-1][4]*(d-C+3+mod)%mod)%mod;
g[i][3]=(g[i-1][0]+g[i-1][2]*(dd-1)%mod+g[i-1][3]*(C-2)%mod+g[i-1][4]*(d-C+3+mod)%mod)%mod;
g[i][4]=(g[i-1][0]+g[i-1][1]+g[i-1][2]*2*(C-3)%mod+g[i-1][3]*2*(C-3)%mod+g[i-1][4]*(d-(2*C-7)+mod)%mod)%mod;
//printf("%lld %lld %lld %lld %lld\n",g[i][0],g[i][1],g[i][2],g[i][3],g[i][4]);
}
}
int check(int a,int b,int c,int d){
if(a==c && b==d) return 0;
if(a==d && b==c) return 1;
if(a==c || b==d) return 2;
if(a==d || b==c) return 3;
return 4;
}
void solve(int x,int y){
op^=1;memset(dp[op],0,sizeof(dp[op]));
int a=A[x],b=B[x],c=A[y],d=B[y];
if(a && b && c && d) dp[op][d]=sum[op^1]*g[y-x-1][check(a,b,c,d)]%mod;
else if(a && b){
for(int i=1;i<=C;i++) if(i!=c+d)
dp[op][i]=sum[op^1]*g[y-x-1][check(a,b,!c?i:c,!d?i:d)]%mod;
}
else if(c && d){
dp[op][d]=((sum[op^1]-dp[op^1][c]-dp[op^1][d])%mod+mod)*g[y-x-1][check(a,b,c,d)]%mod;
(dp[op][d]+=dp[op^1][c]*g[y-x-1][check(!a?c:a,!b?c:b,c,d)]%mod)%=mod;
(dp[op][d]+=dp[op^1][d]*g[y-x-1][check(!a?d:a,!b?d:b,c,d)]%mod)%=mod;
}
else{
for(int i=1;i<=C;i++) if(i!=c+d){
dp[op][i]=(sum[op^1]-dp[op^1][i]-dp[op^1][c+d]+mod+mod)%mod*g[y-x-1][check(a,b,!c?i:c,!d?i:d)]%mod;
(dp[op][i]+=dp[op^1][i]*g[y-x-1][check(!a?i:a,!b?i:b,!c?i:c,!d?i:d)]%mod)%=mod;
(dp[op][i]+=dp[op^1][c+d]*g[y-x-1][check(!a?c+d:a,!b?c+d:b,!c?i:c,!d?i:d)]%mod)%=mod;
}
}
sum[op]=0;for(int i=1;i<=C;i++) (sum[op]+=dp[op][i])%=mod;
}
int main(){
scanf("%d %d",&n,&C);prepare();
data=(1ll*(C-2)*(C-3)+2*(C-1)-1)%mod;
for(int i=1;i<=n;i++) scanf("%d",&A[i]);
for(int i=1;i<=n;i++) scanf("%d",&B[i]);
int lef=1,rig=n;
while(!A[lef] && !B[lef]) lef++;
if(lef==n+1) {printf("%lld\n",ksm(data,n-1)*C%mod*(C-1)%mod);return 0;}
while(!A[rig] && !B[rig]) rig--;
if(A[lef] && B[lef])
dp[op][B[lef]]=sum[op]=1;
else{
for(int i=1;i<=C;i++)
dp[op][i]=(i!=(A[lef]|B[lef]));
sum[op]=C-1;
}
for(int i=lef+1,last=lef;i<=n;i++) if(A[i] || B[i]) solve(last,i),last=i;
printf("%lld\n",sum[op]*ksm(data,lef-1+n-rig)%mod);
}