P13818
思路
看到题目中的条件,可依先转化。
由于
不妨设
然后就可以把所有
又因为
然后考虑开桶存储每一个数的两个为
然后考虑动态规划。
定义
答案可以在枚举每个数时计算。
对于每一个数,设它的两位二进制位在第
则答案将增加
因为这样拼成的一定合法。
复杂度
代码
#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
typedef long long ll;
const int N=300005,L=125;
__int128 a[N];
int cnt[L][L];//cnt:f
void read (__int128& ret) {
ret = 0; int f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -f; ch = getchar();}
while (ch >= '0' && ch <= '9') ret = ret * 10 + ch - '0', ch = getchar();
ret *= f;
}
int popcnt(__int128 x)
{
int cnt=0;
while(x)
{
cnt++;
x-=x&(-x);
}
return cnt;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m=0;
cin>>n;
for(int i=0;i<L;i++)
for(int j=0;j<L;j++)
cnt[i][j]=0;
for(int i=1;i<=n;i++)
{
__int128 x;
read(x);
if(popcnt(x)<=2)a[++m]=x;//只用存储肯能对答案造成贡献的
}
n=m;
ll ans=0;
for(int i=1;i<=n;i++)
{
__int128 u=a[i];
int x=0,y=0,p=0;
while(u)
{
p++;
if(u&1)
{
if(!x)x=p;
else y=p;
}
u>>=1;
}//得到x,y
for(int j=0;j<L;j++)
{
ans+=cnt[j][x]*cnt[j][y];//一定不要再这里取模!
}
cnt[x][y]++;
cnt[y][x]++;
}
cout<<ans%MOD<<'\n';
}
return 0;
}