专栏文章
P13818
P13818题解参与者 2已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @mio5kkd8
- 此快照首次捕获于
- 2025/12/02 13:43 3 个月前
- 此快照最后确认于
- 2025/12/02 13:43 3 个月前
思路
看到题目中的条件,可依先转化。
由于 ,,,。所以 ,,。
不妨设 ,若 ,又因为 所以 ,所以 ,不符合题意,所以得证。
然后就可以把所有 的数先删掉,然后在计算。
又因为 表式一个数的二进制表示中 的个数,所以这样的数不会太多。具体的,不会超过 个。
然后考虑开桶存储每一个数的两个为 二进制位在哪位,如果只有一个为 二进制位,另一个数位用零代替。
然后考虑动态规划。
定义 表示一个位 的二进制位在第 项,另一个在第 项的个数。
答案可以在枚举每个数时计算。
对于每一个数,设它的两位二进制位在第 位和第 位。
则答案将增加 。
因为这样拼成的一定合法。
复杂度 ,略微卡常可过。
代码
CPP#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;
}
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...