来自codechef的GOODPROB,算法是什么?

GOODPROB from codechef, what's the algo?

本文关键字:算法 是什么 GOODPROB codechef 来自      更新时间:2023-10-16

我只是在解决问题,然后发现了这个

给定一个由N个整数组成的数组A - A1, A2.... an。你必须找到Σ MAX(i,j) * F(i,j)的值,其中1≤i <j≤n>

MAX(i,j)定义为MAX(Ai,Ai+1,…Aj)。

F(i,j)定义为:

如果(Ai&Aj) = Aj or (Ai&Aj) = Ai

F(i,j) = 1F(i,j)等于0,否则。在这里,为位与操作符。

参考:GOODPROB

我写了一个相当简单的解决方案,得到了40分,即它不能在所需的2秒时间内处理大量输入。

这是我的代码

#include <iostream>
using namespace std;
int max(int *A, int x,int y){
    int m=A[x];
    while(x<=y){
        if(A[x]>m)
            m=A[x];
        x++;
    }
    return m;
}
int F(int *A,int i,int j){
    return ((A[i]&A[j]) == A[j] or (A[i]&A[j]) == A[i])?1:0;
    }
int main() {
    long N;
    cin>>N;
    int *A = new int[N];
    for(int i=0;i<N; i++)
        cin>>A[i];
    long m=0;
    for(int j=0;j<N;j++)
        for(int i=0;i<j; i++)
            m+= F(A,i,j)?max(A,i,j)*F(A,i,j):0;
    cout<<m<<endl;
    return 0;
} 

我查看了成功的提交,但那些让我感到恐慌。对于这个看起来相当简单的问题,我甚至无法想象这么大的解决方案。有谁能想出一个简单易懂的解决方案吗?

好吧,这并没有真正给你一个有效的算法,但评论部分并没有给出最好的格式选项。

我发现了一些小的优化可能性。你有时会在不需要的时候重复语句。

m+= F(A,i,j)?max(A,i,j)*F(A,i,j):0;

这里可以存储F(A,i,j)的结果,并且只调用该函数两次(函数调用可能会很昂贵)。

return ((A[i]&A[j]) == A[j] or (A[i]&A[j]) == A[i])?1:0;

A[i]&A[j]也是如此。您可以预先存储结果。

就是你当前算法中的一些小问题。他们对你有多大的帮助/提高你必须衡量你自己。

您正在线性地找到数组范围内的最大值。这样做会在您的整体复杂性中增加 0 (n)因素。由于你正在使用嵌套循环并从这些循环中调用max,你的总体时间复杂度将是O(n^3)

可以通过使用段树数据结构来显著降低这个因素。使用段树可以在O(log(n))时间范围内找到最大值。将整体复杂度降低到O(n^2 * log(n))关于范围最大/最小查询的教程

使用段树的范围最小查询