すべてのサブセットの積を取る最速のアルゴリズム


23

n配列内の数値が与えられた場合(整数であるとは想定できません)、sizeのすべてのサブセットの積を計算したいと思いますn-1

これは、すべての数値を乗算してから、数値がゼロでない限り、各数値で順番に除算することで実行できます。ただし、分割を行わずにこれをどのくらい迅速に行うことができますか?

除算を許可しない場合、サイズn-1のすべてのサブセットの積を計算するために必要な算術演算(乗算や加算など)の最小数はどれくらいですか?

明らかに(n-1)*n乗算で行うことができます。

明確にするために、出力はn異なる製品であり、許可されるメモリへの読み取りと書き込み以外の操作は乗算、加算、減算のみです。

入力は、3つの数字を持っている場合2,3,5、出力は3つの数字である15 = 3*510 = 2*56 = 2*3

勝利基準

回答は、コードが使用する算術演算の数の正確な式を与える必要がありnます。人生をシンプルにするために、私はn = 1000あなたのフォーミュラにプラグインしてそのスコアを判断します。低いほど良い。

コードの正確な式を作成するのが難しすぎる場合は、それを実行してn = 1000、コード内の算術演算をカウントできます。ただし、正確な式が最適です。

n=1000簡単に比較できるように、回答にスコアを追加してください。


4
1の乗算を無料としてカウントできますか?そうでなければ、これを行うカスタム乗算関数を定義します。
xnor

3
数字を十分な数のスペーサー0桁と連結して、多数の乗算を並行して行うことはルールに反しますか?
-xnor

1
インデックスなどの操作はカウントさ+ますか?この場合、配列のインデックス付けもカウントされますか?(これは、追加および間接参照のためのすべての構文糖の後にあるため)。
-nore

2
@nore OK私は次のように渡します:)何らかの方法で入力を伴う算術演算を数えるだけです。
アーサー

1
明らかに、あなたはそれを行うことができます(n-1)*n乗算あなたが意味(n-2)*n右、?
ルイスメンドー

回答:


25

Python、3(n-2)操作、スコア= 2994

l = list(map(float, input().split()))
n = len(l)

left = [0] * len(l)
right = [0] * len(l)
left[0] = l[0]
right[-1] = l[-1]
for i in range(1,len(l)-1):
  left[i] = l[i] * left[i - 1]
  right[-i-1] = l[-i-1] * right[-i]

result = [0] * len(l)
result[-1] = left[-2]
result[0] = right[1]
for i in range(1, len(l) - 1):
  result[i] = left[i - 1] * right[i+1]

print(result)

配列leftおよびrightは、それぞれ左および右からの配列の累積積を含みます。

編集:乗算のみを使用する場合、n> = 2に必要な操作の最適数が3(n-2)であることの証明。

これは帰納法で行います。上記のアルゴリズムにより、n> = 2の場合、3(n-2)が必要な乗算の数の下限であることを証明する必要があります。

n = 2の場合、少なくとも0 = 3(2-2)回の乗算が必要なので、結果は簡単です。

n> 2とし、n-1個の要素に対して、少なくとも3(n-3)回の乗​​算が必要だと仮定します。k個の乗算を伴うn個の要素の解を考えてみましょう。次に、これらの要素の最後を1であるかのように削除し、すべての乗算を直接単純化します。除算は許可されていないため、他の要素のn-2の積を得るための中間値として使用することはできないため、他のすべての要素の積につながる乗算も必要ありません。これにより、l回の乗算と、n-1個の要素の解が残ります。

帰納仮説により、l> = 3(n-3)が得られます。

次に、削除された乗算の数を見てみましょう。それらの1つは、最後を除くすべての要素の積につながるものでした。さらに、最後の要素は少なくとも2つの乗算で直接使用されました。1つだけで使用された場合、他の要素の積で構成される中間結果を乗算するときに使用されました。一般性を失うことなく、この中間結果には製品の最初の要素が含まれていたとします。次に、最後の要素を含むすべての製品が最後の要素であるか、最初の要素を含むため、最初の要素以外のすべての要素の製品を取得する方法はありません。

したがって、k> = l + 3> = 3(n-2)となり、定理が証明されます。


8
これが判明Haskellでとてもきれいf l = zipWith (*) (scanl (*) 1 l) (scanr (*) 1 $ tail l)
-xnor

コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
デニス

12

ハスケル、スコア2994

group :: Num a => [a] -> [[a]]
group (a:b:t) = [a,b] : group t
group [a] = [[a]]
group [] = []

(%) :: (Num a, Eq a) => a -> a -> a
a % 1 = a
1 % b = b
a % b = a * b

prod_one_or_two :: (Num a, Eq a) => [a] -> a
prod_one_or_two [a, b] = a % b
prod_one_or_two [x] = x

insert_new_value :: (Num a, Eq a) => ([a], a) -> [a]
insert_new_value ([a, b], c) = [c % b, c % a]
insert_new_value ([x], c) = [c]

products_but_one :: (Num a, Eq a) => [a] -> [a]
products_but_one [a] = [1]
products_but_one l = 
    do combination <- combinations ; insert_new_value combination
    where 
        pairs = group l
        subresults = products_but_one $ map prod_one_or_two pairs
        combinations = zip pairs subresults

オンラインでお試しください!

リストが与えられたとしましょう[a,b,c,d,e,f,g,h]。最初にペアにグループ化します[[a,b],[c,d],[e,f],[g,h]]。次に、pairs製品の半分のサイズのリストを再帰的に取得して、subresults

[a*b, c*d, e*f, g*h] -> [(c*d)*(e*f)*(g*h), (a*b)*(e*f)*(g*h), (a*b)*(c*d)*(g*h), (a*b)*(c*d)*(e*f)]

最初の要素を取得し、(c*d)*(e*f)*(g*h)それをbandでaそれぞれ乗算すると、除くすべてaとすべて以外の積を取得しますb。すべてのペアに対してこれを行い、そのペアが欠落している再帰的な結果、最終結果を取得します。奇数長の場合は、奇数要素を再帰ステップにペアで渡さずに特別に処理され、返される残りの要素の積は、それなしの積になります。

乗算の数は、ペアリング製品、再帰呼び出し、および個々の要素を持つ製品の乗算t(n)です。これは奇数を与えます。奇数のより正確なカウントを使用し、ベースケースでの乗算を無視すると、のスコアが得られます。n/2t(n/2)nt(n) = 1.5 * n + t(n/2)nn12997n=1000


これはすごく素敵。
アーサー

私の答えのようにスコアが2994ではなく2995である理由は、後で切り捨てられる2のべき乗以外のケースでもすべての数値の積を計算するためだと思います。おそらく慎重に処理するproducts_but_one'と、正しい長さの何かを返すことでそれを避けることができます。
-nore

@nore私は、基本ケース1に乗算するのが無料であることを忘れたため、カウントに余分な乗算があったことに気付きました。パディング1は物事に影響を与えなかったと思いますが、それらを使用しないようにアルゴリズムをクリーンアップしました。
-xnor

このコードは、入力が整数であると想定していますか?

@Lembikありますが、オプションの型注釈のみです。それらをすべてに変更しますfloat
-xnor

9

ハスケル、スコア9974

partition :: [Float] -> ([Float], [Float])
partition = foldr (\a (l1,l2) -> (l2, a:l1)) ([],[])

(%) :: Float -> Float -> Float
a % 1 = a
1 % b = b
a % b = a*b

merge :: (Float, [Float]) -> (Float, [Float]) -> (Float, [Float])
merge (p1,r1) (p2, r2) = (p1%p2, map(%p1)r2 ++ map(%p2)r1)

missing_products' :: [Float] -> (Float, [Float])
missing_products' [a] = (a,[1])
missing_products' l = merge res1 res2
    where
        (l1, l2) = partition l
        res1 = missing_products' l1
        res2 = missing_products' l2

missing_products :: [Float] -> [Float]
missing_products = snd . missing_products'

オンラインでお試しください!

マージソートを非常に連想させる、分割統治戦略。インデックス付けを行いません。

この関数partitionは、パーティションの反対側に交互の要素を配置することにより、リストを可能な限り均等に分割します。(p,r)各半分の結果を、r欠落している製品のリスト、およびp製品全体と再帰的にマージします。

完全なリストの出力では、不足している要素は半分になければなりません。その要素が欠落している製品は、それが入っている半分の1つの欠落製品に、残りの半分の完全な製品を掛けたものです。そのため、1つの欠損のある各製品に残りの半分の完全な製品を掛けて、結果のリストを作成しmap(*p1)r2 ++ map(*p2)r1)ます。これはn乗算を行いnます。ここでは長さです。またp1*p2、将来の使用のために新しい全製品を作成する必要があります。これにより、乗算がさらに1増えます。

これは、操作の数のための一般的な再帰与えますt(n)nさえを:t(n) = n + 1 + 2 * t(n/2)。奇数のものは似ていますが、サブリストの1つが1大きくなっています。再帰を実行するn*(log_2(n) + 1)と、乗算が得られますが、奇数/偶数の区別はその正確な値に影響します。までの値は、そのショートカットまたはケースのバリアントを定義することでt(3)乗算しないことにより改善されます。1(%)(*)_*11*_

これによりが9975乗算されn=1000ます。Haskellの怠は、外側の層の未使用の製品全体がについて計算されないことを意味すると考えてい9974ます。間違えた場合は、明示的に省略できます。


あなたは1分前に​​タイムスタンプで私を打ちました。
-nore

数式を正確に計算するのが難しい場合は、ただ実行n = 1000してコード内の算術演算をカウントしてください。
アーサー

私たちのコードは基本的に同じであるため、どのように到達したのか理解でき9974ず、9975乗算は行いませんn = 1000(製品全体を外側の層で計算する場合)。1テストに使用した入力にaを含めましたか?
-nore

@noreあなたは正しいです、私は1つオフでした。乗算関数呼び出しの数に対して再帰を行うコードを書きました。通話を直接カウントする方が信頼性が高いでしょう-Haskellでどのように私がそれをするのか誰にも分かりますか?
-xnor

1
@xnorあなたが使用することができますtraceから、Debug.Traceキャッチオールと| trace "call!" False = undefinedガード、私は思います。しかし、これはunsafePerformIO内部で使用されるため、実際にはそれほど改善されていません。
ソハムチョードリー

6

ハスケル、スコア2994

group :: [a] -> Either [(a, a)] (a, [(a, a)])
group [] = Left []
group (a : l) = case group l of
  Left pairs -> Right (a, pairs)
  Right (b, pairs) -> Left ((a, b) : pairs)

products_but_one :: Num a => [a] -> [a]
products_but_one [_] = [1]
products_but_one [a, b] = [b, a]
products_but_one l = case group l of
  Left pairs ->
    let subresults =
          products_but_one [a * b | (a, b) <- pairs]
    in do ((a, b), c) <- zip pairs subresults; [c * b, c * a]
  Right (extra, pairs) ->
    let subresult : subresults =
          products_but_one (extra : [a * b | (a, b) <- pairs])
    in subresult : do ((a, b), c) <- zip pairs subresults; [c * b, c * a]

オンラインでお試しください!

使い方

これは、xnorのアルゴリズムのクリーンアップバージョンで、奇妙なケースをより簡単な方法で処理します(編集:xnorが同じ方法でクリーンアップしたように見えます)。

[a、b、c、d、e、f、g]↦
[a、bc、de、fg]↦
[(bc)(de)(fg)、a(de)(fg)、a(bc)( fg)、a(bc)(de)] by再帰↦
[(bc)(de)(fg)、a(de)(fg)c、a(de)(fg)b、a(bc)(fg) e、a(bc)(fg)d、a(bc)(de)g、a(bc)(de)f]

[a、b、c、d、e、f、g、h]↦
[ab、cd、ef、gh]↦
[(cd)(ef)(gh)、(ab)(ef)(gh)、( ab)(cd)(gh)、(ab)(cd)(ef)] by再帰↦
[(cd)(ef)(gh)b、(cd)(ef)(gh)a、(ab)(ef )(gh)d、(ab)(ef)(gh)c、(ab)(cd)(gh)f、(ab)(cd)(gh)e、(ab)(cd)(ef)h、 (ab)(cd)(ef)g]。


「(あなたは彼らが整数であると仮定することはできません)、アレイ内の数字Nを考えると、」我々は、彼らが整数であると仮定することはできません

5

O(n log n)操作、スコア= 9974

バイナリツリーで動作します。

Python

l = list(map(int, input().split()))
n = len(l)

p = [0] * n + l
for i in range(n - 1, 1, -1):
  p[i] = p[i + i] * p[i + i+1]

def mul(x, y):
  if y == None:
    return x
  return x * y

r = [None] * n + [[None]] * n
for i in range(n - 1, 0, -1):
  r[i] = [mul(p[i + i + 1], x) for x in r[i + i]] + [mul(p[i + i], x) for x in r[i + i + 1]]

u = r[1]
j = 1
while j <= n:
  j += j
print(u[n+n-j:] + u[:n+n-j])

これには、リストの追加操作、および入力値ではない数値の一部の算術演算も必要です。それが重要かどうかわかりません。このmul関数は、ベースケースのn個の操作を保存し、1を掛けて無駄にしないようにします。いずれの場合も、これはO(n log n)操作です。入力数の算術演算のみをカウントする場合、正確な式はj = floor(log_2(n))次のとおり j * (2^(j + 1) - n) + (j + 1) * (2 * n - 2^(j + 1)) - 2です。

外積を計算しないという考えで1つの操作を保存してくれた@xnorに感謝します!

最後の部分は、欠落している用語の順に製品を出力することです。


数式を正確に計算するのが難しい場合は、ただ実行n = 1000してコード内の算術演算をカウントしてください。
アーサー

10975回の操作をカウントしました...?
ハイパーニュートリノ

p[i] = p[i + i] * p[i + i+1]カウントされません
-HyperNeutrino

これはn log2 n + n操作に関するものです(O(nlogn)btw
HyperNeutrino

@HyperNeutrinoの操作 p[i] = p[i + i] * p[i + i + 1]、乗算の最適化によって保存する必要があります。ただし、数が多すぎるかもしれません。
-nore

3

O((n-2)* n)= O(n 2):自明な解決策

これは、各サブセットを乗算する単純なソリューションです。

Python

def product(array): # Requires len(array) - 1 multiplication operations
    if not array: return 1
    result = array[0]
    for value in array[1:]:
        result *= value
    return result

def getSubsetProducts(array):
    products = []
    for index in range(len(array)): # calls product len(array) times, each time calling on an array of size len(array) - 1, which means len(array) - 2 multiplication operations called len(array) times
        products.append(product(array[:index] + array[index + 1:]))
    return products

これにも必要なことに注意してください nリスト追加操作。それが重要かどうかわかりません。それが許可されていない場合は、product(array[:index] + array[index + 1:])に置き換えてproduct(array[:index]) * product(array[index + 1:])、式をに変更できますO((n-1)*n)


回答に独自のスコアを追加できます。この場合、998 * 1000。
アーサー

product関数O(n)操作は必要ありませんか?アレイ内の各要素に対して1つ(これは容易に変更することができるalthought O(n-1)
ローマGRAF

@RomanGräfはい。O(n-1)に変更しますが、指摘してくれてありがとう。
ハイパーニュートリノ

これはatomic-code-golfに変更されました...
エリックアウトゴルファー

@EriktheOutgolferそれが今私のスコアを作っているのは何ですか?私が露骨に愚かでない限り、タグと仕様は今互いに矛盾していませんか?
ハイパーニュートリノ

3

Python、7540

三者間マージ戦略。まだ大規模なマージを行うことで、これよりもさらにうまくいくと思います。O(n log n)です。

編集:ミスカウントを修正しました。

count = 0
def prod(a, b):
    if a == 1: return b
    if b == 1: return a
    global count
    count += 1
    return a * b

def tri_merge(subs1, subs2, subs3):
    total1, missing1 = subs1
    total2, missing2 = subs2
    total3, missing3 = subs3

    prod12 = prod(total1, total2)
    prod13 = prod(total1, total3)
    prod23 = prod(total2, total3)

    new_missing1 = [prod(m1, prod23) for m1 in missing1]
    new_missing2 = [prod(m2, prod13) for m2 in missing2]
    new_missing3 = [prod(m3, prod12) for m3 in missing3]

    return prod(prod12, total3), new_missing1 + new_missing2 + new_missing3

def tri_partition(nums):
    split_size = len(nums) // 3
    a = nums[:split_size]
    second_split_length = split_size + (len(nums) % 3 == 2)
    b = nums[split_size:split_size + second_split_length]
    c = nums[split_size + second_split_length:]
    return a, b, c

def missing_products(nums):
    if len(nums) == 1: return nums[0], [1]
    if len(nums) == 0: return 1, []
    subs = [missing_products(part) for part in tri_partition(nums)]
    return tri_merge(*subs)

def verify(nums, res):
    actual_product = 1
    for num in nums:
        actual_product *= num
    actual_missing = [actual_product // num for num in nums]
    return actual_missing == res[1] and actual_product == res[0]

nums = range(2, int(input()) + 2)
res = missing_products(nums)

print("Verified?", verify(nums, res))
if max(res[1]) <= 10**10: print(res[1])

print(len(nums), count)

関連する関数はでmissing_products、これは製品全体と、要素が欠落しているすべての製品を提供します。


乗算をカウントしましたtri_mergeか?また、2 * split_size + ...in tri_partitionをに置き換えることもできますsplit_size + split_size + ...
ローマン

@RomanGräf私はあなたの提案に従ってそれを再構築しました。
isaacg

1

dc、スコア2994

#!/usr/bin/dc -f

# How it works:
# The required products are
#
#   (b × c × d × e × ... × x × y × z)
# (a) × (c × d × e × ... × x × y × z)
# (a × b) × (d × e × ... × x × y × z)
# ...
# (a × b × c × d × e × ... × x) × (z)
# (a × b × c × d × e × ... × x × y)
#
# We calculate each parenthesised term by
# multiplying the one above (on the left) or below
# (on the right), for 2(n-2) calculations, followed
# by the n-2 non-parenthesised multiplications
# giving a total of 3(n-2) operations.

# Read input from stdin
?

# We will store input values into stack 'a' and
# accumulated product into stack 'b'.  Initialise
# stack b with the last value read.
sb

# Turnaround function at limit of recursion: print
# accumulated 'b' value (containing b..z above).
[Lbn[ ]nq]sG

# Recursive function - on the way in, we stack up
# 'a' values and multiply up the 'b' values.  On
# the way out, we multiply up the 'a' values and
# multiply each by the corresponding 'b' value.
[dSalb*Sb
z1=G
lFx
dLb*n[ ]n
La*]dsFx

# Do the last a*b multiplication
dLb*n[ ]n

# And we have one final 'a' value that doesn't have a
# corresponding 'b':
La*n

私は整数の比較を仮定しています z1=(最後の値に達したときに再帰を終了する)は無料でいます。これはforeach、他の言語と同様です。

デモンストレーション

for i in '2 3 5' '2 3 5 7' '0 2 3 5' '0 0 1 2 3 4'
do printf '%s => ' "$i"; ./127147.dc <<<"$i"; echo
done
2 3 5 => 15 10 6
2 3 5 7 => 105 70 42 30
0 2 3 5 => 30 0 0 0
0 0 1 2 3 4 => 0 0 0 0 0 0

大小の入力があるデモ:

./127147.dc <<<'.0000000000000000000542101086242752217003726400434970855712890625 1 18446744073709551616'
18446744073709551616 1.0000000000000000000000000000000000000000000000000000000000000000 .0000000000000000000542101086242752217003726400434970855712890625

1

C ++、スコア:5990、O([2NlogN] / 3)

この実装では、バイナリツリールックアップテーブルを使用します。私の最初の実装はO(NlogN)でしたが、最後の最適化では、すべての配列要素からペアを引いた積を調べ、+ 2乗算で1日を節約しました。これはまださらに最適化できると思います。おそらくさらに16%...

デバッグトレースをいくつか残しましたが、それはそれらを書き換えるよりも削除する方が簡単だからです:)

[編集]実際の複雑さは100のO([2NlogN] / 3)で測定されます。実際には小さなセットのO(NlogN)より少し悪いですが、配列が大きくなるにつれてO([NlogN] / 2)に向かう傾向があります。 100万個の要素のセットに対して非常に大きなO(0.57.NlogN)。

#include "stdafx.h"
#include <vector>
#include <iostream>
#include <random>
#include <cstdlib>

using DataType = long double;

using DataVector = std::vector<DataType>;

struct ProductTree
{
    std::vector<DataVector> tree_;
    size_t ops_{ 0 };

    ProductTree(const DataVector& v) : ProductTree(v.begin(), v.end()) {}
    ProductTree(DataVector::const_iterator first, DataVector::const_iterator last)
    {
        Build(first, last);
    }

    void Build(DataVector::const_iterator first, DataVector::const_iterator last)
    {
        tree_.emplace_back(DataVector(first, last));

        auto size = std::distance(first, last);
        for (auto n = size; n >= 2; n >>= 1)
        {
            first = tree_.back().begin();
            last = tree_.back().end();

            DataVector v;
            v.reserve(n);
            while (first != last) // steps in pairs
            {
                auto x = *(first++);
                if (first != last)
                {
                    ++ops_;
                    x *= *(first++); // could optimize this out,small gain
                }
                v.push_back(x);
            }
            tree_.emplace_back(v);
        }
    }

    // O(NlogN) implementation... 
    DataVector Prod()
    {
        DataVector result(tree_[0].size());
        for (size_t i = 0; i < tree_[0].size(); ++i)
        {
            auto depth = tree_.size() - 1;
            auto k = i >> depth;
            result[i] = ProductAtDepth(i, depth);
        }
        return result;
    }

    DataType ProductAtDepth(size_t index, size_t depth) 
    {
        if (depth == 0)
        {
            return ((index ^ 1) < tree_[depth].size())
                ? tree_[depth][index ^ 1]
                : 1;
        }
        auto k = (index >> depth) ^ 1;

        if ((k < tree_[depth].size()))
        {
            ++ops_;
            return tree_[depth][k] * ProductAtDepth(index, depth - 1);
        }
        return ProductAtDepth(index, depth - 1);
    }    

    // O([3NlogN]/2) implementation... 
    DataVector Prod2()
    {
        DataVector result(tree_[0].size());
        for (size_t i = 0; i < tree_[0].size(); ++i)    // steps in pairs
        {
            auto depth = tree_.size() - 1;
            auto k = i >> depth;
            auto x = ProductAtDepth2(i, depth);
            if (i + 1 < tree_[0].size())
            {
                ops_ += 2;
                result[i + 1] = tree_[0][i] * x;
                result[i] = tree_[0][i + 1] * x;
                ++i;
            }
            else
            {
                result[i] = x;
            }
        }
        return result;
    }

    DataType ProductAtDepth2(size_t index, size_t depth)
    {
        if (depth == 1)
        {
            index = (index >> 1) ^ 1;
            return (index < tree_[depth].size())
                ? tree_[depth][index]
                : 1;
        }
        auto k = (index >> depth) ^ 1;

        if ((k < tree_[depth].size()))
        {
            ++ops_;
            return tree_[depth][k] * ProductAtDepth2(index, depth - 1);
        }
        return ProductAtDepth2(index, depth - 1);
    }

};


int main()
{
    //srand(time());

    DataVector data;
    for (int i = 0; i < 1000; ++i)
    {
        auto x = rand() & 0x3;          // avoiding overflow and zero vaolues for testing
        data.push_back((x) ? x : 1);
    }

    //for (int i = 0; i < 6; ++i)
    //{
    //  data.push_back(i + 1);
    //}

    //std::cout << "data:[";
    //for (auto val : data)
    //{
    //  std::cout << val << ",";
    //}
    //std::cout << "]\n";

    ProductTree pt(data);
    DataVector result = pt.Prod2();

    //std::cout << "result:[";
    //for (auto val : result)
    //{
    //  std::cout << val << ",";
    //}
    //std::cout << "]\n";
    std::cout << "N = " << data.size() << " Operations :" << pt.ops_ << '\n';

    pt.ops_ = 0;
    result = pt.Prod();

    //std::cout << "result:[";
    //for (auto val : result)
    //{
    //  std::cout << val << ",";
    //}
    //std::cout << "]\n";

    std::cout << "N = " << data.size() << " Operations :" << pt.ops_ << '\n';

    return 0;
}

完全を期すために、@ noreのアルゴリズムを追加しています。それは本当に素晴らしく、最速です。

class ProductFlat
{
private:
    size_t ops_{ 0 };

    void InitTables(const DataVector& v, DataVector& left, DataVector& right)
    {
        if (v.size() < 2)
        {
            return;
        }

        left.resize(v.size() - 1);
        right.resize(v.size() - 1);

        auto l = left.begin();
        auto r = right.rbegin();
        auto ol = v.begin();
        auto or = v.rbegin();

        *l = *ol++;
        *r = *or++;
        if (ol == v.end())
        {
            return;
        }

        while (ol + 1 != v.end())
        {
            ops_ += 2;
            *l = *l++ * *ol++;
            *r = *r++ * *or++;
        }
    }

public:
    DataVector Prod(const DataVector& v)
    {
        if (v.size() < 2)
        {
            return v;
        }

        DataVector result, left, right;
        InitTables(v, left, right);

        auto l = left.begin();
        auto r = right.begin();
        result.push_back(*r++);
        while (r != right.end())
        {
            ++ops_;
            result.push_back(*l++ * *r++);
        }
        result.push_back(*l++);
        return result;
    }

    auto Ops() const
    {
        return ops_;
    }
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.