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;
}
这样写虽然可以通过但是有风险:
实际上是数据不强,擦着边过得,因为n最大1e5,我们用了两个for循环,已经1e10了。
另外就是ans要开long long,不开过不了:
此时完美就要用另一种思路:
因此
又因为
所以
变式为:
k最大为31 (整形最大31位),因此我们可以枚举 ,这是一个很小的计算量,一共只需要枚举32次
然后我们用,会得到一个aj,如果aj之前出现过,那我们就把aj出现的次数统计一下,就是能与ai匹配的aj的个数:
code
Tips:
实际上就是枚举2^k ,1左移一位就是扩大2倍,即 ,左移k位就是扩大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。