码蹄集 - MT3149 · AND - 数据不是很强,暴力剪枝就能骗AC
Posted Tisfy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了码蹄集 - MT3149 · AND - 数据不是很强,暴力剪枝就能骗AC相关的知识,希望对你有一定的参考价值。
传送门
AND
时间限制:1秒
空间限制:64M
题目描述
给出一个长n的数列a,设
p
i
,
j
=
a
i
p_i,j=a_i
pi,j=ai and
a
i
+
1
a_i+1
ai+1 and ……and
a
j
a_j
aj,
求
∑
i
=
1
n
∑
j
=
i
n
p
i
,
j
\\sum_i=1^n\\sum_j=i^np_i,j
∑i=1n∑j=inpi,j
输入描述
第一行一个整数n,表示数列长度。
第二行n个整数表示数列a。
数据范围
数据范围
1 ≤ n ≤ 100000 , 0 ≤ a i ≤ 1 0 9 1\\le n \\le100000,0\\le a_i \\le 10^9 1≤n≤100000,0≤ai≤109
输出描述
一个整数表示答案。
样例一
输入
5
5 8 4 5 6
输出
40
前言
这道题数据比较弱,我本来想着先暴力一发看看能过多少组,结果纯暴力就过了 7 7 7组。
然后我就想看看加上剪枝能过多少,结果就AC了。
然后我也就没有再多想更低复杂度的方法。
本篇博客所采用方法复杂度是 O ( n 2 ) O(n^2) O(n2),截止到2022年6月30日18:38分均可通过本题。
不知道以后是否会有新的测试数据。
题目分析
首先让我们想想如何暴力。最初的暴力复杂度是 O ( n 3 ) O(n^3) O(n3):
从1到n枚举i
从i到n枚举j
从i AND 到j
但是很容易想到,在 j j j从 i i i枚举到 n n n的时候,新的结果可在旧的结果的基础上用 O ( 1 ) O(1) O(1)的时间复杂度求出。
用专业点的语言来讲,就是:
在已知 p i , j p_i,j pi,j的前提下,可以用 O ( 1 ) O(1) O(1)的时间复杂度求出 p i , j + 1 p_i,j+1 pi,j+1
其公式为: p i , j + 1 = p i , j & a [ j + 1 ] p_i,j+1=p_i,j \\& a[j+1] pi,j+1=pi,j&a[j+1]
这样,时间复杂度就将为了 O ( n 2 ) O(n^2) O(n2)
int a[100010];
int main()
int n;
cin >> n;
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
ll ans = 0;
for (int i = 0; i < n; i++)
ll k = a[i];
for (int j = i; j < n; j++)
k &= a[j]; // pi,j+1=pi,j & a[j+1]
ans += k;
cout << ans << endl;
return 0;
这样就已经可以通过 3 3 3组数据了。
剪枝
不难发现,如果 p i , j = 0 p_i,j=0 pi,j=0,那么 p i , j + 1 p_i,j+1 pi,j+1、 p i , j + 2 p_i,j+2 pi,j+2、 ⋯ \\cdots ⋯、 p i , n p_i,n pi,n全部为 0 0 0
因为 0 A N D 任 何 数 都 为 0 0\\ AND\\ 任何数\\ 都为0 0 AND 任何数 都为0 。
因此上述代码中在 k = 0 k=0 k=0的时候,我们直接 b r e a k break break即可。
我就这么一试,就AC了。
但是看官请注意,但凡有一组全部是 1 1 1的 1 e 5 1e5 1e5的数据,上述方法就通过不了
AC代码
#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int a[100010];
int main()
int n;
cin >> n;
fi (i, 0, n) // for (int i = 0; i < n; i++)
cd(a[i]); // scanf a[i]
ll ans = 0;
for (int i = 0; i < n; i++)
ll k = a[i];
for (int j = i; j < n; j++)
k &= a[j];
if (!k)
break; // 剪枝
ans += k;
cout << ans << endl;
return 0;
每周提前更新菁英班周赛题解,点关注,不迷路
原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/125546150
以上是关于码蹄集 - MT3149 · AND - 数据不是很强,暴力剪枝就能骗AC的主要内容,如果未能解决你的问题,请参考以下文章