LOJ6469 Magic(trie+)
阿新 • • 發佈:2018-12-04
紀念我菜的真實的一場模擬賽
首先看到這個題目,一開始就很毒瘤。一定是沒有辦法直接做的。
我們考慮轉化問題
假設,我們選擇列舉
,其中
是
的若干次方,那麼我們只需要求有多少對異或完比
大的數,那麼就是
對於答案的貢獻了。
那麼應該怎麼求比多少對呢?
!!!trie!!!
對於trie的每個節點,我們維護他的子樹裡面的數的個數,記為
我們考慮把每一個串放進trie裡面去跑,如果當前這個數的這一位是1,而10的幾次方對應的也是1的話,那麼當前位只能選擇0,即 ,如果10的幾次方對應的位是0的話,那麼這一位選擇0一定是全都滿足條件的,是1的不一定,那麼我們可以把0的那邊記錄進答案裡面,然後走1的那邊試一試,
另一種情況同理
不過需要注意的是,因為我們的貪心的放,所以必須從高位到低位來迴圈
int query(int now,int lim)
{
int root=1;
int ans=0;
for (register int i=62;i>=0;--i)
{
if (!root) break;
if (now&(1ll << i))
{
if (lim & (1ll << i))
root=ch[root][0];
else
ans=ans+sum[ch[root][0]],root=ch[root][1];
}
else
{
if (lim&(1ll <<i))
root=ch[root][1];
else
ans=ans+sum[ch[root][1]],root=ch[root][0];
}
}
return ans;
}
對於每一個,我們都這麼算,那麼最後的
,就是我們要的答案
因為每一對,我們會重複算兩遍
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 1e5+1e2;
int n;
int a[maxn];
int ch[7000000][3];
int tot=1;
int ans;
int sum[7000000];
void insert(int now)
{
int root=1;
for (register int i=62;i>=0;--i)
{
int x = (now & (1ll << i));
if (x!=0) x=1;
else x=0;
if (!ch[root][x]) ch[root][x]=++tot;
root=ch[root][x];
sum[root]++;
}
//cout<<tot<<endl;
}
int query(int now,int lim)
{
int root=1;
int ans=0;
for (register int i=62;i>=0;--i)
{
if (!root) break;
if (now&(1ll << i))
{
if (lim & (1ll << i))
root=ch[root][0];
else
ans=ans+sum[ch[root][0]],root=ch[root][1];
}
else
{
if (lim&(1ll <<i))
root=ch[root][1];
else
ans=ans+sum[ch[root][1]],root=ch[root][0];
}
}
return ans;
}
int qsm(int i,int j)
{
//if (j==0) return 0;
int ans=1;
while (j)
{
if (j&1) ans=ans*i;
i=i*i;
j>>=1;
}
return ans;
}
signed main()
{
n=read();
for (int i=1;i<=n;++i) a[i]=read();
for (register int i=1;i<=n;++i) insert(a[i]);
int pre=0;
for (register int i=0;i<=18;++i)
{
int cnt=0;
for (register int j=1;j<=n;++j)
{
cnt=cnt+query(a[j],qsm(10,i)-1);
//cout<<i<<" "<<cnt<<endl;
}
ans=ans+cnt;
}
cout<<ans/2;
return 0;
}