状压(DP)加矩阵优化。
关于这道题的出题人。。。
他当年应该被打死了吧。。。
题目中的第(1)行第(k)列指的是从(0)开始标号下的第(1)行第(k)列,也就是说,这一题存在第(0)行第(0)列!
搞什么不好,非得要搞题意理解。。。
设(f[i][j])为第(i)行,状态为(j)时的答案(我们只压了一行)。
如果(j)可以转移到(k),则有(f[i+1][k]=f[i][j]+f[i+1][k])。
这里我们发现,两个集合是否可以转移,这是固定的,也就是说,我们可以矩阵快速幂优化一下。
矩阵记得清零。。。
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int f=1,w=0;char x=0;
while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
return w*f;
}
const int M=7;
const int p=1LL<<32;
const int N=1e6+10;
int n,m,K,C,Max,ans,f[1<<M];
vector<int> Atk[3];
struct Matrix
{
int A[80][80];
inline Matrix (){ memset(A,0,sizeof(A));}
inline Matrix operator * (const Matrix &B) const
{
Matrix C;
for(register int i=0;i<Max;++i)
for(register int j=0;j<Max;++j)
for(register int k=0;k<Max;++k)
C.A[i][j]=(C.A[i][j]%p+(A[i][k]*B.A[k][j])%p+p)%p;
return C;
}
} Trn;
inline Matrix ksm(Matrix b,int k)
{
Matrix a=b;k--;
while(k)
{
if(k&1) a=a*b;
b=b*b;k>>=1;
}
return a;
}
inline bool Check(int x,int y)
{
for(register int i=0;i<m;++i)
if((x>>i)&1)
{
for(register int j=0;j<(int)Atk[1].size();++j)
if(0<=i+Atk[1][j]&&i+Atk[1][j]<m)
if((x>>(i+Atk[1][j]))&1) return 0;
for(register int j=0;j<(int)Atk[2].size();++j)
if(0<=i+Atk[2][j]&&i+Atk[2][j]<m)
if((y>>(i+Atk[2][j]))&1) return 0;
}
for(register int i=0;i<m;++i)
if((y>>i)&1)
{
for(register int j=0;j<(int)Atk[1].size();++j)
if(0<=i+Atk[1][j]&&i+Atk[1][j]<m)
if((y>>(i+Atk[1][j]))&1) return 0;
for(register int j=0;j<(int)Atk[0].size();++j)
if(0<=i+Atk[0][j]&&i+Atk[0][j]<m)
if((x>>(i+Atk[0][j]))&1) return 0;
}
return 1;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
#endif
n=read(),m=read(),C=read(),K=read();Max=1LL<<m;
for(register int i=0;i<3;++i)
for(register int j=0;j<C;++j)
if(read()&&(j!=K||i!=1)) Atk[i].push_back(j-K);
for(register int i=0;i<Max;++i)
for(register int j=0;j<Max;++j)
Trn.A[i][j]=Check(i,j);
for(register int i=0;i<Max;++i) f[i]=Trn.A[0][i];Trn=ksm(Trn,n);
for(register int i=0;i<Max;++i) ans=(ans%p+(f[i]%p*Trn.A[i][0]%p+p)%p+p)%p;
printf("%lld",(ans+p)%p);
}