题意
从n个数中挑选k个数做排列(是排列哦,如果两个数相同不判重),如果这k个数中,相邻的两个数异或的二进制结果中有3的倍数个1,这样的排列就是满足条件的。最后输出满足条件的排列的个数。
题解
处理出一个矩阵G,g[i][j] 表示num[i] 和 num[j] 异或满足条件
可知 G2 = G*G 中的 G2[i][j]就是以num[i]开头, num[j] 结尾,且k=3的满足条件的个数
G的n次方就是,Gn[i][j]就是以num[i]开头, num[j] 结尾,且k=n+1的满足条件的个数
用 矩阵快速幂 求出G(k-1)的所有元素和即为所求
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#define mod 1000000007
using namespace std;
typedef long long ll;
const ll MAX_N = 110LL;
ll n,k;
ll num[MAX_N];
struct graph
{
ll a[MAX_N][MAX_N];
friend graph operator * (graph &A, graph &B)
{
graph C;
for(ll i=0;i<n;i++)
{
for(ll j=0;j<n;j++)
{
C.a[i][j] = (ll)0;
for(ll k=0;k<n;k++)
{
C.a[i][j] = (C.a[i][j] + (A.a[i][k]*B.a[k][j])%mod) % mod;
}
}
}
return C;
}
void init()
{
for(ll i=0;i<n;i++)
{
a[i][i] = 1;
for(ll j=i+1;j<n;j++)
{
a[i][j] = a[j][i] = 0;
}
}
}
friend ostream& operator << (ostream &io, const graph &A)
{
for(ll i=0;i<n;i++)
{
for(ll j=0;j<n;j++)
{
io<<A.a[i][j]<<" ";
}
io<<endl;
}
return io;
}
};
graph mod_pow(graph tg, ll kk)
{
graph g;
g.init();
while(kk)
{
if(kk%2)
{
g = g*tg;
}
kk = kk>>1;
tg = tg*tg;
}
return g;
}
int main()
{
while(scanf("%I64d%I64d",&n,&k)!=EOF)
{
for(ll i=0;i<n;i++)
{
scanf("%I64d",&num[i]);
}
graph g2;
for(ll i=0;i<n;i++)
{
g2.a[i][i] = 1LL;
for(ll j=i+1;j<n;j++)
{
ll x = num[i]^num[j];
ll cnt = 0LL;
while(x)
{
cnt += x&1;
x = x>>1;
}
if(cnt%3==0)
{
g2.a[i][j] = g2.a[j][i] = 1;
}
else
g2.a[i][j] = g2.a[j][i] = 0;
}
}
graph gk = mod_pow(g2, k-1);
ll ans=0;
for(ll i=0;i<n;i++)
{
for(ll j=0;j<n;j++)
{
ans = (ans+ gk.a[i][j])%mod;
}
}
cout<<ans<<endl;
}
return 0;
}