蓝桥杯第七场小白赛 4.可结合的元素对【算法赛】 知识点:数学推论

604 阅读1分钟

4.可结合的元素对【算法赛】 - 蓝桥云课 (lanqiao.cn)

这道题就是考知不知道lowbit()函数:

#include<bits/stdc++.h>
using namespace std;
#define LL long long

int lowbit(int x)
{
  return x&-x;
}


int main()
{

  cin.tie(nullptr)->ios::sync_with_stdio(false);

   int n;cin>>n;
   vector<int>a(n+1);
   for(int i=1;i<=n;i++)
   {
     cin>>a[i];
   }

LL ans = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            if (lowbit(a[i] + a[j]) == a[i] + a[j])ans += 1;
        }
    }

   cout<<ans<<endl;

  return 0;
}

这样写虽然可以通过但是有风险: image.png

实际上是数据不强,擦着边过得,因为n最大1e5,我们用了两个for循环,已经1e10了。

另外就是ans要开long long,不开过不了: image.png

此时完美就要用另一种思路:

lowbit(x)=2klowbit(x)=2^k

因此 lowbit(ai+aj)=2klowbit(ai+aj)=2^k

又因为 lowbit(ai+aj)=ai+ajlowbit(ai+aj)=ai+aj

所以ai+aj=2k ai+aj=2^k

变式为: aj=2kaiaj=2^k-ai

k最大为31 (整形最大31位),因此我们可以枚举2k 2^k ,这是一个很小的计算量,一共只需要枚举32次

然后我们用2kai 2^k-ai,会得到一个aj,如果aj之前出现过,那我们就把aj出现的次数统计一下,就是能与ai匹配的aj的个数:

code

Tips:

for(intk=1;k<=30;k++)1<<2k for (int k = 1; k <= 30; k++)1<<2^k

实际上就是枚举2^k ,1左移一位就是扩大2倍,即212^1 ,左移k位就是扩大k倍,就是2k2^k

#include<bits/stdc++.h>
#define int long long
using namespace std;

int a[100010];
unordered_map<int, int> h;

signed main()
{
    int n;
    cin >> n;

    for (int i = 1; i <= n; i++)cin >> a[i];
    sort(a + 1, a + n + 1);

    int res = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int k = 1; k <= 30; k++)//枚举所有可能的k
        {
            int aj = (1 << k) - a[i];//aj为能与a[i]配对的数
            if (h.find(aj) != h.end())res += h[aj];//能找到aj
        }
        h[a[i]]++;
    }
    cout << res;

    return 0;
}

这个时间复杂度是32nlogn。其中32是枚举的2^k,哈希是logn。