码蹄集 - 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=1nj=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 1n100000,0ai109


输出描述

一个整数表示答案。


样例一

输入

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的主要内容,如果未能解决你的问题,请参考以下文章

码蹄集 - MT2093 · 回文数数位

码蹄集 - MT2065 - 整数大小比较

码蹄集 - MT2201 · 各位之和

码蹄集 - MT3521 - X/Y

码蹄集 - MT3182 - 填矩阵

码蹄集 - MT1258 · 特殊整数