题解 P7341【『MdOI R4』Phoenix】
前言:
感谢zyk对我的指导,我才得以写出这题。
2k 代码调了将近 3h 才调出来,看起来我的代码能力还需提高。
题解:
不难发现,一个满足条件的把集合排列好的排列,必须满足对于
设 Solve(v,t) 考虑
考虑找到一个
对于
考虑先找到那些不存在另一个数
如果直接按这些
拍一拍会发现问题出在有的数非常讨厌,比如一个数
具体如何统计答案建议自行思考。实现细节可以参考代码。
时间复杂度:
code:
/*
zyk txdy zyk txdy
zyk txdy zyk txdy
zyk txdy zyk txdy
zyk txdy zyk txdy
zyk txdy zyk txdy
zyk txdy zyk txdy
zyk txdy zyk txdy
*/
const int mod=998244353;
int T,n,m,fac[N];
ull a[N];
void init(int n){
fac[0]=1;
for(int i=1;i<=n;++i){
fac[i]=1LL*fac[i-1]*i%mod;
}
}
struct Union_Set{
int f[64],s[64];
void init(int n){
for(int i=0;i<n;++i)f[i]=i,s[i]=1;
}
int getf(int x){
return f[x]==x?x:f[x]=getf(f[x]);
}
int Merge(int x,int y){
int fx=getf(x),fy=getf(y);
if(fx==fy)return 0;
s[fx]+=s[fy],s[fy]=0;
f[fy]=fx;
return 1;
}
};
int Solve(vector<ull> &p,ull t){
ull z=0;
static int cnt[64];
memset(cnt,0,sizeof(cnt));
bool same=true;
for(int i=1;i<(int)p.size();++i){
if(p[i]^p[0]){same=false;break;}
}
if(same)return fac[p.size()];
for(auto x:p){
for(int i=0;i<m;++i){
if(x>>i&1)++cnt[i];
}
}
for(int i=0;i<m;++i){
if(t>>i&1){
ull all=(1uLL<<m)-1;
for(auto x:p){
if(x>>i&1)all&=x;
}
bool ok=true;
for(int j=0;j<m&&ok;++j){
if(i==j||cnt[j]<cnt[i]||(cnt[j]==cnt[i]&&i<j))continue;
if(all>>j&1){
ok=false;break;
}
}
if(ok)z|=1uLL<<i;
}
}
while(true){
bool qwq=false;
for(int i=0;i<m;++i){
if(t>>i&1&&!(z>>i&1)){
ull tmp=~0uLL;
for(auto x:p){
if(x>>i&1){
ull g=(x&z);
if(~tmp&&tmp^g){
z|=1uLL<<i;qwq=true;
break;
}
tmp=g;
}
}
}
}
if(!qwq)break;
}
int res=1;
map<ull,vector<ull> > mp;
int rem=__builtin_popcountll(z);
for(auto x:p){
if(x){
mp[x&z].push_back(x^(x&z));
}
else ++rem;
}
Union_Set S;
S.init(m);
for(auto [d,s]:mp){
res=1LL*res*Solve(s,t^z)%mod;
for(int i=0;i<m;++i){
if(d>>i&1){
for(int j=0;j<m;++j){
if(d>>j&1)rem-=S.Merge(i,j);
}
}
}
}
for(int i=0;i<m;++i){
if(z>>i&1&&S.s[i]>1)(res<<=1)%=mod;
}
return 1LL*res*fac[rem]%mod;
}
int main(){
init(100000);
T=read();
int cnt=0;
while(T--){
++cnt;
n=read(),m=read();
vector<ull> all;
for(int i=1;i<=n;++i){
all.push_back(read());
}
printf("%d\n",Solve(all,(1uLL<<m)-1));
}
return 0;
}