题解:P13818 「LDOI R3」泡泡抗特
废话(可跳过)
somewhere over the rainbow way up high.
there's a land that I heard of once in a lullaby.
only blue. only blue.
愛讓人,好憂鬱。
我的心。我的心。藍藍的。
题目背景出自陶喆 soul power 演唱会版本的《沙滩》。赞美出题人。
调了超级久,最后发现先模再除和先除再模是不一样的,卡了两天。。
正文
根据异或零元律的性质推出以下三点:
:::info[零元律]
若
一个最直接的想法是枚举
但实际上不是
根据
那么我们在输入的时候,将满足
这时候我们枚举
你说这样枚举有啥用?还不是要看每个数的相对位置?
大可不必。注意到我们要满足的三元组仅需要下标递增,也就是说参与运算的数怎么排都行。那我们找到三个符合条件的数时,我们必定能找到一个下标递增的排列方式。基于此,每对
具体实现的时候,我用
手玩发现只有两个
模拟的时候分类讨论一下即可。还要注意三元组中每两个数都会被计入
# include <bits/stdc++.h>
# define mod 1000000007
using namespace std;
long long mp[125][125];
bool chk[125][125][125][125];
__int128 arr1[300005];
struct new_arr
{
int id1,id2;
};
struct new_arr arr2[300005];
long long ans;
int newn;
void redi (__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;
} // 调用 redi(x) 以读入变量 x。
void add(__int128 x) // 筛选
{
int id1=125,id2=125; // 第一个1出现的位置,第二个1出现的位置
int idx=1; // 当前二进制位置
__int128 tmp = x;
while (x > 0)
{
if ((x&1) == 1)
{
if (id1 == 125) id1 = idx;
else if(id2 == 125) id2 = idx;
else return ;
}
x = x>>1;
idx++;
}
if (!mp[id1][id2])
{
arr2[newn].id1 = id1;
arr2[newn++].id2 = id2;
}
mp[id1][id2]++;
return ;
}
int main (void)
{
int T;
scanf ("%d",&T);
while (T--)
{
int n;
scanf ("%d",&n);
for (int i=0;i<n;i++)
{
redi(arr1[i]);
add(arr1[i]);
}
for (int i=0;i<newn;i++)
{
for (int j=i+1;j<newn;j++)
{
int id1,id2;
if (arr2[i].id1 == arr2[j].id1) // 其中两位相同
{
id1 = min(arr2[i].id2,arr2[j].id2);
id2 = max(arr2[i].id2,arr2[j].id2);
}
else if (arr2[i].id1 == arr2[j].id2)
{
id1 = min(arr2[i].id2,arr2[j].id1);
id2 = max(arr2[i].id2,arr2[j].id1);
}
else if (arr2[i].id2 == arr2[j].id1)
{
id1 = min(arr2[i].id1,arr2[j].id2);
id2 = max(arr2[i].id1,arr2[j].id2);
}
else if (arr2[i].id2 == arr2[j].id2)
{
id1 = min(arr2[i].id1,arr2[j].id1);
id2 = max(arr2[i].id1,arr2[j].id1);
}
else
{
continue;
}
long long n1 = mp[id1][id2];
long long n2 = mp[arr2[i].id1][arr2[i].id2];
long long n3 = mp[arr2[j].id1][arr2[j].id2];
ans += n1*n2*n3;
}
}
printf ("%lld\n",(ans/3) % mod);
for (int i=0;i<125;i++) //重置
{
for (int j=0;j<125;j++)
{
mp[i][j] = 0;
}
}
newn=0;
ans=0;
}
return 0;
}