【问题标题】:Good triplets sum and divisor好的三元组和和除数
【发布时间】:2019-09-24 06:28:33
【问题描述】:

给定一个包含 N 个整数的数组 A。找到好的三元组(i, j, k) 的数量,其中ijk 都是不同的索引,例如0 < i , j , k <= N。一个好的三元组(i, j, k) 是一个三元组,使得总和, S = A[i] + A[j] + A[k],可被 A[i]A[j]A[k] 之一整除。

三元组(i,j,k) 的数组值为(A[i], A[j], A[k])

输入:N=4 A=[1,2,2,1]

输出:12

解释:S=2+2+1=5 只能被三元组中的数字1 整除,而数组值1, 1, 2 的三元组不是一个好的三元组,因为S = 4 可以被所有三个整除。所以有两个三元组(1,2,2)(2,2,1)。查看作为索引的i,j,k 值。因此,有 12 种可能的三元组索引,它们的数组值可以是 221。他们是: (1, 2, 3), (1, 3, 2), (2, 1, 3), (3, 1, 2), (2, 3, 1), (3, 2, 1), (2, 3, 4), (2, 4, 3), (3, 2, 4), (4, 2, 3), (3, 4, 2), (4, 3, 2)。 我试过这个(但我想降低时间复杂度):

def good_triplets (arr, n):
    c=0
    for i in range(0,n-2):
        for j in range(i+1,n-1):
            for k in range(j+1,n):
                sum=arr[i]+arr[j]+arr[k]
                if(sum%arr[i]==0 and sum%arr[j]!=0 and sum%arr[k]!=0):
                    c=c+1
                elif(sum%arr[j]==0 and sum%arr[k]!=0 and sum%arr[i]!=0):
                    c=c+1
                elif(sum%arr[k]==0 and sum%arr[i]!=0 and sum%arr[j]!=0):
                    c=c+1
    return(c*6)

n = int(input())
arr = []
for i in range(n) : 
    x = int(input())
    arr.append(x)
out_ = good_triplets(arr, n)
print (out_)

【问题讨论】:

  • 到目前为止你尝试了什么?
  • 问题是什么?向我们展示 yozu 到目前为止所做的尝试以及您遇到的问题。
  • 使用了 3 个嵌套的 for 循环,然后 if else 条件..由于 3 个嵌套的 for 循环时间复杂度=O(n3)
  • 我想要更有效的解决方案而不使用 itertools 组合
  • 你的谓词很奇怪。 1 < i , j , k < N 表示索引 N 或 1 都不可能,但您在示例中同时使用索引 4 和 1:|

标签: python arrays algorithm


【解决方案1】:

这是以 O(10^6) 复杂度运行的解决方案。提示在 A[i] 中。


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

vector<vector<int>> getpossiblenumbers(){
    int i,j,k;
    vector<vector<int>> v;
    for(i=1;i<=100;i++){
        for(j=1;j<=100;j++){
            for(k=1;k<=100;k++)
            {
                int sum=i+j+k;
                if((sum%i==0 && sum%j!=0 && sum%k!=0)||
                    (sum%j==0 && sum%i!=0 && sum%k!=0)||
                    (sum%k==0 && sum%i!=0 && sum%j!=0))
                v.push_back({i,j,k});
            }
        }
    }
    return v;
}

在本节中,我所做的是运行 3 个循环,检查所有可能的三元组在给定约束下的所有可能性,这些约束应该只能被 i、j 和 k 之一整除。三元组的所有可能组合都不会太多。

long long good_triplets (vector<int> arr, int n) {
   vector<vector<int>> v = getpossiblenumbers();
   long long i,j,k,ans=0;
   map<long long,long long> m1;
   for(i=0;i<n;i++){
       m1[arr[i]]++;
   }
   for(int i=0;i<v.size();i++){
       if(m1[v[i][0]]>0 && m1[v[i][1]]>0 && m1[v[i][2]]>0)
       {
            if(v[i][0]==v[i][1])
            ans+=((m1[v[i][0]]*(m1[v[i][1]]-1)*m1[v[i][2]]));
            else if(v[i][1]==v[i][2])
            ans+=((m1[v[i][0]]*(m1[v[i][1]]-1)*m1[v[i][2]]));
            else if(v[i][0]==v[i][2])
            ans+=((m1[v[i][1]]*(m1[v[i][0]]-1)*m1[v[i][2]]));
            else
            ans+=(m1[v[i][0]]*m1[v[i][1]]*m1[v[i][2]]);
       }    
   }
   return ans;
}

在这个 good_triplet 方法中,我首先将每个数字的频率计数存储在地图中。
然后用 3 个可能的 i, j, k 迭代我们之前创建的向量。 所有 3 个 i, j, k 不能相等,因为 sum 只能被 1 整除,我们已经在 getpossiblenumbers 函数中处理了这一点。
但是当i、j 和 k 中的两个是相等的,就像我在上面的 3 个案例中所做的那样处理计数。继续添加答案变量。

int main() {

    ios::sync_with_stdio(0);
    cin.tie(0);
    int n;
    cin >> n;
    vector<int> arr(n);
    for(int i_arr=0; i_arr<n; i_arr++)
    {
        cin >> arr[i_arr];
    }
    long long out_;
    out_ = good_triplets(arr, n);
    cout << out_;
}

【讨论】:

    【解决方案2】:

    根据问题,数组中可能存在重复值和唯一值,例如。 [6,6,4,3]。 为了获得优化的解决方案,该算法分为两个主要部分——唯一值、重复值。 (主要思想)删除重复项并保持计数。数字小于 100。因此时间复杂度会降低很多。

    def good_triplets(arr, n):
        dict1 = {}  // to keep count of each element
        nums = []   // to keep unique entries of each element
        for i in range(0, n):
            if dict1.get(int(arr[i])) is None:
                dict1[int(arr[i])] = 1
                nums.append(int(arr[i]))
            else:
                dict1[int(arr[i])] = dict1[int(arr[i])] + 1
        count = 0   //count of good triplets
        n = len(nums)
    
        // for every entry occuring atleast once in the given array (unique entry) [6,4,3]
        for i in range(0, n):
            for j in range(i + 1, n):
                sum = nums[i] + nums[j]
                for k in range(j + 1, n):
                    sum += nums[k]
                    c = 0
                    if sum % nums[i] == 0:
                        c += 1
                    if sum % nums[j] == 0:
                        c += 1
                    if sum % nums[k] == 0:
                        c += 1
                    if c == 1:
                        count += dict1[nums[i]] * dict1[nums[j]] * dict1[nums[k]]  //total count depends on how many times i,j,k appears in the actual array
    
        // for every entry occuring more than once in the given array (duplicate entries) eg.[6]
        for i in range(0, n):
            if dict1[nums[i]] < 2: // not to be executed for unique entries as they are already taken care of
                continue
            for j in range(0, n):
                if i == j:
                    continue
                sum = nums[i] * 2 + nums[j] // i will be the duplicate element and j will be our third element in the triplet
                if sum % nums[i] != 0 and sum % nums[j] ==0:  // if the sum is divisible only by the third element (j)
                    count += ((dict1[nums[i]] * (dict1[nums[i]] - 1)) / 2) * dict1[nums[j]]
        return count*6
    
    n = int(input())
    arr = []
    for i in range(n):
        x = input()
        arr.append(x)
    
    good_triplet_count = good_triplets(arr, n)
    print(good_triplet_count)
    

    【讨论】:

      【解决方案3】:
      #include <bits/stdc++.h>
      using namespace std;
      
      int binomialCoeff(int n, int k) 
      { 
          vector<int> C(k+1,0); 
      
          C[0] = 1;  // nC0 is 1 
      
          for (int i = 1; i <= n; i++) 
          { 
              // Compute next row of pascal triangle using 
              // the previous row 
              for (int j = min(i, k); j > 0; j--) 
                  C[j] = C[j] + C[j-1]; 
          } 
          return C[k]; 
      }
      
      long countGoodTriplets(vector<int> a)
      {
          int n = a.size();
          int threeFactorial=6;
          int elSize = 100;
          long goodTriplets = 0;
          vector<int> count(elSize,0);
          for(int i=0;i<n;i++)
          {
              count[a[i]]++;
          }
      
          for(int i=1;i<elSize-1;i++)
          {
              for(int j=i+1;j<elSize;j++)
              {
                  for(int k=j+1;k<elSize+1;k++)
                  {
                          if(count[i]!=0 && count[j]!=0&& count[k]!=0)
                          {
                          int flag=0;
                          //int sum = i+j+k;
                          if((i+j)%k==0) //sum%k
                          flag++;
                          if((k+j)%i==0)//sum%i
                          flag++;
                          if((i+k)%j==0)//sum%j
                          flag++;
      
                          if(flag==1)
                          {
                              //cout<<i<<" "<<j<<" "<<k<<endl;
                              goodTriplets += threeFactorial;
                          }
                      }
      
                  }
              }
          }
            for(int i=1;i<elSize;i++)
          {
              for(int j=i+1;j<elSize+1;j++)
              {
      
                 if( count[i]>1 && ((2*i))%j ==0 && (j%i!=0)) 
                 {
                     goodTriplets+=(threeFactorial * (binomialCoeff(count[i],2)));
                 }
                 if( count[j]>1 && ((2*j))%i ==0 && (i%j!=0)) 
                 {
                     goodTriplets+=(threeFactorial * (binomialCoeff(count[j],2)));
                 }
      
              }
          }
          return goodTriplets;
      }
      
      int main() {
          //code
          vector<int> vect{ 1,2,4 }; 
          cout<<calc(vect);
          return 0;
      }
      

      【讨论】:

      • 预期输出错误。你能查一下吗?
      猜你喜欢
      • 1970-01-01
      • 2020-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多