You are given a polynomial of degree N with integer coefficients. Your task is to find the value of this polynomial at some K different integers, modulo 786433.
Input
The first line of the input contains an integer N denoting the degree of the polynomial.
The following line of each test case contains (N+1) integers denoting the coefficients of the polynomial. The ith numbers in this line denotes the coefficient a_(i-1) in the polynomial a_0 + a_1 × x_1 + a_2 × x_2 + ... + a_N × x_N.
The following line contains a single integer Q denoting the number of queries.
The jth of the following Q lines contains an integer number x_j denoting the query.
Output
For each query, output a single line containing the answer to the corresponding query. In other words, the jth line of the output should have an integer equal to a_0 + a_1 × x_j + a_2 × x_j^2 + ... + a_N × x_j^N modulo 786433.
Constraints and Subtasks
0 ≤ a_i, x_j < 786433
Subtask #1 (37 points): 0 ≤ N, Q ≤ 1000
Subtask #2 (63 points): 0 ≤ N, Q ≤ 2.5 × 10^5
Example
Input:
2
1 2 3
3
7
8
9
Output:
162
209
262
Explanation
Example case 1.
Query 1: 1 + 2 × 7 + 3 × 7 × 7 = 162
Query 2: 1 + 2 × 8 + 3 × 8 × 8 = 209
Query 3: 1 + 2 × 9 + 3 × 9 × 9 = 262
Here is the code that runs in O(n log n) time. I use Fast Fourier Transform to multiply the two polynomials.
Why do I need to use the modulo 786433 operator for all calculations? I understand that this might relate to int overflow? It this normal in competitive programming questions?
#include <cstdio>
#include <algorithm>
#include <vector>
#include <sstream>
#include <iostream>
using namespace std;
#define all(a) (a).begin(),(a).end()
#define pb push_back
#define sz(a) ((int)(a).size())
#define mp make_pair
#define fi first
#define se second
typedef pair<int, int> pint;
typedef long long ll;
typedef vector<int> vi;
#define MOD 786433
#define MAGIC (3*(1<<18))
const int root = 10;
void fft(vi &a, int wn = root)
{
int n = sz(a);
if (n == 3)
{
int a1 = a[0] + a[1] + a[2];
int a2 = (a[0] + a[1] * 1LL * root + a[2] * (root * 1LL * root)) % MOD;
a[1] = a1;
a[2] = a2;
return;
}
vi a0(n / 2), a1(n / 2);
for (int i = 0, j = 0; i<n; i += 2, ++j)
{
a0[j] = a[i];
a1[j] = a[i + 1];
}
int wnp = (wn * 1LL * wn) % MOD;
fft(a0, wnp);
fft(a1, wnp);
int w = 1;
for (int i = 0; i<n / 2; ++i) {
int twiddle = (w * 1LL * a1[i]) % MOD;
a[i] = (a0[i] + twiddle) % MOD;
a[i + n / 2] = (a0[i] - twiddle + MOD) % MOD;
w = (w * 1LL * wn) % MOD;
}
}
int n;
vi coef;
void poly(stringstream& ss)
{
ss >> n;
n++;
for (int i = 0; i<n; i++)
{
int x;
ss >> x;
coef.pb(x);
}
while (sz(coef)<MAGIC)
coef.pb(0);
vi ntt = coef;
fft(ntt);
vector<pint> sm;
sm.pb(mp(0, coef[0]));
int pr = 1;
for (int i = 0; i<sz(ntt); i++)
{
sm.pb(mp(pr, ntt[i]));
pr = (pr * 1LL * root) % MOD;
}
sort(all(sm));
int q;
ss >> q;
while (q--)
{
int x;
ss >> x;
int lo = 0, hi = sz(sm) - 1;
while (lo<hi)
{
int m = (lo + hi) / 2;
if (sm[m].fi<x)
lo = m + 1;
else
hi = m;
}
printf("%d\n", sm[lo].se);
}
}
void test1()
{
stringstream ss;
{
int degree = 2;
ss << degree << "\n";
string coefficients{ "1 2 3" };
ss << coefficients << "\n";
int NoQueries = 3;
ss << NoQueries << "\n";
int query = 7;
ss << query << "\n";
query = 8;
ss << query << "\n";
query = 9;
ss << query << "\n";
}
poly(ss);
}
int main()
{
test1();
return 0;
}
BTW.: This question is from the July 2016 challenge # code chef
Re
” Why do I need to use the modulo 786433 operator for all calculations? I understand that this might relate to int overflow? It this normal in competitive programming questions?
Yes, it's to avoid overflow.
And yes, it's normal in programming problem sets and competitions.
Related
Consider a very long K-digit number N with digits d0, d1, ..., dK-1 (in decimal notation; d0 is the most significant and dK-1 the least significant digit). This number is so large that we can't give it to you on the input explicitly; instead, you are only given its starting digits and a way to construct the remainder of the number.
Specifically, you are given d0 and d1; for each i ≥ 2, di is the sum of all preceding (more significant) digits, modulo 10 — more formally, the following formula must hold:
Determine if N is a multiple of 3.
Input
The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
The first and only line of each test case contains three space-separated integers K, d0 and d1.
Output
For each test case, print a single line containing the string "YES" (without quotes) if the number N is a multiple of 3 or "NO" (without quotes) otherwise.
Constraints
1 ≤ T ≤ 1000
2 ≤ K ≤ 1012
1 ≤ d0 ≤ 9
0 ≤ d1 ≤ 9
Example
Input:
3
5 3 4
13 8 1
760399384224 5 1
Output:
NO
YES
YES
Explanation
Example case 1: The whole number N is 34748, which is not divisible by 3, so the answer is NO.
Example case 2: The whole number N is 8198624862486, which is divisible by 3, so the answer is YES.
Question Ended
In this question, in the example test case given, we have k=760399384224, d0=5, and d1=1. Now we know that a number is multiple of 3 if the sum of it’s digits is a multiple of 3. So applying it here, we separate the number n into 3 parts,
Part 1: First 3 digits -> 516 , (5+1+6) mod 3 ==0, so rem1 = 0.
Part 2: Next will be (k-3)/4 times repetition of (2486) ,or,rem2 = ((2+4+8+6)*((k-3)/4))%3= 1
Part 3: the last (k-3)%4 =1 digits which will be 2 (from 2486 repetition) , so rem3 = 2%3=2
So the final answer should be (rem1+rem2+rem3)%3
and I wrote the following code for this logic:
#include<iostream>
#define ll long long
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
ll k;
cin>>k;
int d0,d1;
cin>>d0>>d1;
int d2 = (d0+d1)%10;
int d[4];
d[0] = (d0+d1+d2)%10;
d[1] = (2*d[0])%10;
d[2] = (2*d[1])%10;
d[3] = (2*d[2])%10;
ll rem1 = (d0+d1+d2)%3,rem2,rem3=0;
rem2 = (20*(((k-3)/4)%3))%3;
ll x = (k-3)%4;
if(x!=0)
{
for(int i=0; i<x; ++i)
rem3+=d[i];
rem3 = rem3%3;
}
else
rem3 =0;
if(k==2)
{
rem1 = (d0+d1)%3;
rem2=0;
rem3=0;
}
if((rem1+rem2+rem3)%3==0)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
Now they’re giving me WA in their test cases. And I cant think of a possible test cases which doesn’t work with this code. So somebody help me out please.
Here's an apparent mismatch. You can probably use this JavaScript code to find more:
function f(k, d0, d1){
let d2 = (d0+d1)%10;
let d = new Array(4).fill(0);
d[0] = (d0+d1+d2)%10;
d[1] = (2*d[0])%10;
d[2] = (2*d[1])%10;
d[3] = (2*d[2])%10;
let rem1 = (d0+d1+d2)%3, rem2, rem3=0;
rem2 = (20*((~~((k-3)/4))%3))%3;
let x = (k-3)%4;
if(x!=0)
{
for(let i=0; i<x; ++i)
rem3+=d[i];
rem3 = rem3%3;
}
else
rem3 =0;
if(k==2)
{
rem1 = (d0+d1)%3;
rem2=0;
rem3=0;
}
if((rem1+rem2+rem3)%3==0)
return true
return false
}
function bruteForce(k, d0, d1){
let d = (d0 + d1) % 10;
let n = 10 * d0 + d1;
for (let i=3; i<=k; i++){
n = 10 * n + d;
d = (2 * d) % 10;
}
return [n % 3 == 0, n];
}
let str = "";
str += "Examples:\n";
str += "(5, 3, 4)\n" + bruteForce(5, 3, 4) + "\n\n";
str += "(13, 8, 1)\n" + bruteForce(13, 8, 1) + "\n\n"
var k = 7;
var mismatch = false;
for (let i=1; i<10; i++){
for (let j=0; j<10; j++){
const _f = f(k, i, j);
const _bruteForce = bruteForce(k, i, j);
if (_bruteForce[0] != _f){
str += "Mismatch:\n" +
`(${ k }, ${ i }, ${ j })\n` +
"f: " + _f +
"\nbruteForce: " + _bruteForce + "\n\n";
mismatch = true;
}
if (mismatch)
break;
}
if (mismatch)
break;
}
console.log(str);
#include <stdio.h>
void isMulti3(long long int K, long long int d0, long long int d1) {
long long int mod1 = (d0 + d1) % 10;
long long int sum_mod1 = d0 + d1 + mod1;
long long int rep = (K-3)/4;
long long int mod2[4];
mod2[0] = (2*mod1) % 10;
mod2[1] = (4*mod1) % 10;
mod2[2] = (8*mod1) % 10;
mod2[3] = (6*mod1) % 10;
long long int sum_mod2 = 0;
for(int i = 0; i < 4; i++) {
sum_mod2 += mod2[i];
}
long long int unrep = (K - 3) % 4;
long long int sum_mod3 = 0;
for(int i = 0; i < unrep; i++) sum_mod3 += mod2[i];
long long int isMod1 = sum_mod1 % 3;
long long int isMod2 = ((rep%3)*(sum_mod2%3)) % 3;
long long int isMod3 = sum_mod3 % 3;
if((isMod1 + (isMod2 + isMod3)%3)% 3 == 0) printf("YES\n");
else printf("NO\n");
}
int main() {
int T;
scanf("%d", &T);
for(int i = 0; i < T; i++) {
long long int K;
long long int d0, d1;
scanf("%lld %lld %lld", &K, &d0, &d1);
if(K == 2) {
if((d0 + d1) % 3 == 0) printf("YES\n");
else printf("NO\n");
}
else isMulti3(K, d0, d1);
}
}
I think you are the same guy who asked the question on the codechef discussion portal.
I answered it there , and I am sharing the link.
[https://discuss.codechef.com/t/dsa-learning-series-multiple-of-3/77174/4?u=nazishkaunain][1]
So the point where you are mistaken is:
You might use the fact:
(a+b+c)mod 3 != a mod 3 + b mod 3 + c mod 3;
But (a + b + c) mod 3 = (a mod 3 + ( b mod 3 + c mod 3) mod 3) mod 3;
And a number n ( n = a + b + c) is divisible by 3 only if n mod 3 = 0 => (a + b + c) mod 3 = 0.
Question is as follows :
Given two numbers n and k. For each number in the interval [1, n], your task is to calculate its largest divisor that is not divisible by k. Print the sum of all these divisors.
Note: k is always a prime number.
t=3*10^5,1<=n<=10^9, 2<=k<=10^9
My approach toward the question:
for every i in range 1 to n, the required divisors is i itself,only when that i is not a multiple of k.
If that i is multiple of k, then we have to find the greatest divisor of a number and match with k. If it does not match, then this divisor is my answer. otherwise, 2nd largest divisor is my answer.
for example,take n=10 and k=2, required divisors for every i in range 1 to 10 is 1, 1, 3, 1, 5, 3, 7, 1, 9, 5. sum of these divisors are 36. So ans=36.
My code,which works for a few test cases and failed for some.
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
ll div2(ll n, ll k) {
if (n % k != 0 || n == 1) {
return n;
}
else {
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
ll aa = n / i;
if (aa % k != 0) {
return aa;
}
}
}
}
return 1;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
ll n, k;
cin >> n >> k;
ll sum = 0, pp;
for (pp = 1; pp <= n; pp++) {
//cout << div2(pp, k);
sum = sum + div2(pp, k);
}
cout << sum << '\n';
}
}
Can someone help me where I am doing wrong or suggest me some faster logic to do this question as some of my test cases is showing TIME LIMIT EXCEED
after looking every possible explanation , i modify my code as follows:
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
ll n, i;
ll k, sum;
cin >> n >> k;
sum = (n * (n + 1)) / 2;
for (i = k; i <= n; i = i + k) {
ll dmax = i / k;
while (dmax % k == 0) {
dmax = dmax / k;
}
sum = (sum - i) + dmax;
}
cout << sum << '\n';
}
}
But still it is giving TIME LIMIT EXCEED for 3 test cases. Someone please help.
Like others already said, look at the constraints: t=3*10^5,1<=n<=10^9, 2<=k<=10^9.
If your test has a complexity O(n), which computing the sum via a loop has, you'll end up doing a t * n ~ 10^14. That's too much.
This challenge is a math one. You'll need to use two facts:
as you already saw, if i = j * k^s with j%k != 0, the largest divisor is j;
sum_{i=1}^t i = (t * (t+1)) / 2
We start with
S = sum(range(1, n)) = n * (n+1) / 2
then for all number of the form k * x we added too much, let's correct:
S = S - sum(k*x for x in range(1, n/k)) + sum(x for x in range(1, n/k))
= S - (k - 1) * (n/k) * (n/k + 1) / 2
continue for number of the form k^2 * x ... then k^p * x until the sum is empty...
Ok, people start writing code, so here's a small Python function:
def so61867604(n, k):
S = (n * (n+1)) // 2
k_pow = k
while k_pow <= n:
up = n // k_pow
S = S - (k - 1) * (up * (up + 1)) // 2
k_pow *= k
return S
and in action here https://repl.it/repls/OlivedrabKeyProjections
In itself this is more of a mathematical problem:
If cur = [1..n], as you have already noticed, the largest divisor = dmax = cur is, if cur % k != 0, otherwise dmax must be < cur. From k we know that it is at most divisible into other prime numbers... Since we want to make sure that dmax is not divisible by k we can do this with a while loop... whereby this is certainly also more elegantly possible (since dmax must be a prime number again due to the prime factorization).
So this should look like this (without guarantee just typed down - maybe I missed something in my thinking):
#include <iostream>
int main() {
unsigned long long n = 10;
unsigned long long k = 2;
for (auto cur_n = decltype(n){1}; cur_n <= n; cur_n++)
{
if (cur_n % k != 0) {
std::cout << "Largest divisor for " << cur_n << ": " << cur_n << " (SELF)" << std::endl;
} else {
unsigned long long dmax= cur_n/k;
while (dmax%k == 0)
dmax= dmax/k;
std::cout << "Largest divisor for " << cur_n << ": " << dmax<< std::endl;
}
}
}
I wonder if something like this is what One Lyner means.
(Note, this code has two errors in it, which are described in the comments, as well as can be elucidated by One Lyner's new code.)
C++ code:
#include <vector>
#include <iostream>
using namespace std;
#define ll long long int
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
ll n;
ll k, _k, result;
vector<ll> powers;
cin >> n >> k;
result = n * (n + 1) / 2;
_k = k;
while (_k <= n) {
powers.push_back(_k);
_k = _k * k;
}
for (ll p : powers) {
ll num_js = n / p;
result -= num_js * (num_js + 1) / 2 * (p - 1);
int i = 0;
while (p * powers[i] <= n) {
result += powers[i] * (p - 1);
i = i + 1;
}
}
cout << result << '\n';
}
}
A Magic Fraction for N is one that has the following properties:
It is a proper fraction (The value is < 1)
It cannot be reduced further (The GCD of the numerator and the denominator is 1)
The product of the numerator and the denominator is factorial of N. i.e. if a/b is the fraction, then a*b = N!
Examples of Magic Fractions are:
1/2 [ gcd(1,2) = 1 and 1*2=2! ]
2/3 [ gcd(2,3) = 1 and 2*3=3! ]
3/8 [ gcd(3,8) = 1 and 3*8=4! ]
2/12 for example, is not a magic fraction, as even though 2*12=4!, gcd(2,12) != 1
And Magic fractions for number 3 are: 2/3 and 1/6 (since both of them satisfy the above criteria, are of the form a/b where a*b = 3!)
Now given a number N, you need to print the total number of magic fractions that exist, for all numbers between 1 and N (include magic fractions for N, too).
Can anybody tell me what is modPow function doing?
Refer the link to see the question, that will give an idea why this code.
using namespace std;
#define ll long long int
#define S(n) scanf("%lld", &n)
ll MOD = 1e18 + 7;
ll modPow(ll a, ll b)
{
ll res = 1;
a %= MOD;
for (; b; b >>= 1) {
if (b & 1)
res = res * a % MOD;
a = a * a % MOD;
}
return res;
}
int main()
{
ll i, j;
ll va = 1;
ll sum = 0;
ll prime[1000] = { 0 };
for (i = 2; i <= 500; i++) {
if (prime[i] == 0)
for (j = 2 * i; j <= 500; j += i)
prime[j] = 1;
}
ll val[600] = { 0 };
val[1] = 0;
val[2] = 1;
ll co = 0;
for (i = 3; i <= 500; i++) {
if (prime[i] == 0) {
co++;
}
ll t1 = modPow(2, co);
val[i] = t1 + val[i - 1];
val[i] %= MOD;
// cout << i << " " << val[i] << "\n";
}
ll n;
S(n);
cout << val[n] << "\n";
}
I am not that skilled or advanced in C++ and I have trouble solving a problem.
I know how to do it mathematically but I can't write the source code, my algorithm is wrong and messy.
So, the problem is that I have to write a code that reads a number ( n ) from the keyboard and then it has to find a sum that is equal to n squared ( n ^ 2 ) and the number of sum's elements has to be equal to n.
For example 3^2 = 9, 3^2 = 2 + 3 + 4, 3 elements and 3^2 is 9 = 2 + 3 + 4.
I had several attempts but none of them were successful.
I know I'm borderline stupid but at least I tried.
If anyone has the time to look over this problem and is willing to help me I'd be very thankful.
1
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
//1,3,5,7,9,11,13,15,17,19,21,23,25,27..
int n;
list<int> l;
cin >> n;
if ( n % 2 == 0 ){
cout << "Wrong." << endl;
}
for ( int i = 1; i <= 99;i+=2){
l.push_back(i);
}
//List is full with 1,3,5,7,9,11,13,15,17,19,21,23,25,27..
list<int>::iterator it = find(begin(l),end(l), n);
}
2
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 3^2 = 2 + 3 + 4
// 7^2 = 4 + 5 + 6 + 7 + 8 + 9 + 10
int n;
int numbers[100];
for (int i = 0; i <= 100; i++){
numbers[i] = i;
}
cin >> n;
int requiredSum;
requiredSum = n * n;
//while(sum < requiredSum){
// for(int i = 1; i < requiredSum; i++){
// sum += i;
// sumnums.push_back(sum);
// }
//}
int sum = 0;
std::vector<int> sumnums;
while(sum < requiredSum){
for(int i = 1; i < requiredSum; i++){
sum += i;
sumnums.push_back(sum);
}
}
for(int i=0; i<sumnums.size(); ++i)
std::cout << sumnums[i] << ' ';
}
Update:
The numbers of the sum have to be consecutive numbers.Like 3 * 3 has to be equal to 2 + 3 + 4 not 3 + 3 + 3.
So, my first try was that I found a rule for each sum.
Like 3 * 3 = 2 + 3 + 4, 5 * 5 = 3 + 4 + 5 + 6 + 7, 7 * 7 = 4 + 5 + 6 + 7 + 8 + 9 + 10.
Every sum starts with the second element of the previous sum and continues for a number of elements equal to n - 1, like 3 * 3 = 2 + 3 + 4, 5 * 5 , the sum for 5 * 5 starts with 3 + another 4 elements.
And another algorithm would be #molbdnilo 's, like 3 * 3 = 3 + 3 + 3 = 3 + 3 + 3 - 1 + 1, 3 * 3 = ( 3 - 1 ) + 3 + ( 3 + 1 ), but then 5 * 5 = (5 - 2) + ( 5 - 1 ) + 5 + 5 + 1 + 5 + 2
Let's do a few special cases by hand.
(The division here is integer division.)
3^2: 9
2 + 3 + 4 = 9
x-1 x x+1
1 is 3/2
5: 25
3 + 4 + 5 + 6 + 7 = 25
x-2 x-1 x x+1 x+2
2 is 5/2
7: 49
4 + 5 + 6 + 7 + 8 + 9 + 10
x-3 x-2 x-1 x x+1 x+2 x+3
3 is 7/2
It appears that we're looking for the sequence from n - n / 2 to n + n / 2.
(Or, equivalently, n / 2 + 1 to n / 2 + n, but I like symmetry.)
Assuming that this is correct (the proof left as an exercise ;-):
int main()
{
int n = 0;
std::cin >> n;
if (n % 2 == 0)
{
std::cout << "Must be odd\n";
return -1;
}
int delta = n / 2;
for (int i = n - delta; i <= n + delta; i++)
{
std::cout << i << " ";
}
std::cout << std::endl;
}
If there is not constraints on what are the elements forming the sum, the simplest solution is just to sum up the number n, n times, which is always n^2.
int main()
{
int n;
cout<<"Enter n: ";
cin >> n;
for(int i=0; i<n-1; i++){
cout<<n<<"+";
}
cout<<n<<"="<<(n*n);
return 0;
}
Firstly, better use std::vector<> than std::list<>, at least while you have less than ~million elements (it will be faster, because of inside structure of the containers).
Secondly, prefer ++i usage, instead of, i++. Specially in situation like that
...for(int i = 1; i < requiredSum; i++)...
Take a look over here
Finally,
the only error you had that you were simply pushing new numbers inside container (std::list, std::vector, etc.) instead of summing them, so
while(sum < requiredSum){
for(int i = 1; i < requiredSum; i++){
sum += i;
sumnums.push_back(sum);
}
change to
// will count our numbers
amountOfNumbers = 1;
while(sum < requiredSum && amountOfNumber < n)
{
sum += amountOfNumbers;
++amountOfNumbers;
}
// we should make -1 to our amount
--amountOfNumber;
// now let's check our requirements...
if(sum == requiredSum && amountOfNumbers == n)
{
cout << "Got it!";
// you can easily cout them, if you wish, because you have amountOfNumbers.
// implementation of that I am leaving for you, because it is not hard ;)
}
else
{
cout << "Damn it!;
}
I assumed that you need sequential sum of numbers that starts from 1 and equals to n*n and their amount equils to n.
If something wrong or need explanation, please, do not hesitate to contact me.
Upd. amountOfNumber < n intead <=
Also, regarding "not starting from 1". You said that you know how do it on paper, than could you provide your algorithm, then we can better understand your problem.
Upd.#2: Correct and simple answer.
Sorry for such a long answer. I came up with a great and simple solution.
Your condition requires this equation x+(x+1)+(x+2)+... = n*n to be true then we can easily find a solution.
nx+ArPrg = nn, where is
ArPrg - Arithmetic progression (ArPrg = ((n-1)*(1+n-1))/2)
After some manipulation with only unknown variable x, our final equation will be
#include <iostream>
int main()
{
int n;
std::cout << "Enter x: ";
std::cin >> n;
auto squareOfN = n * n;
if (n % 2 == 0)
{
std::cout << "Can't count this.\n";
}
auto x = n - (n - 1) / 2;
std::cout << "Our numbers: ";
for (int i = 0; i < n; ++i)
std::cout << x + i << " ";
return 0;
}
Math is cool :)
I have an array with the elements {7,2,1} and the idea is to do 7 * 2 + 7 * 1 + 2 * 1 which is basically this algorithm:
for(int i=0;i<n-1;++i)
for(int k=i+1;k<n;++k)
sum += a[i] * a[k];
Where a is the array in which I have the numbers and n is the number of elements, I need a more efficient algorithm for doing this, and I have no clue how to do it, can someone give me a hand?
Thank you!
You can do better in the general case. Time to do some math. Let's look at the 3-element version, we have:
ab + ac + bc
= 1/2 * (2ab + 2ac + 2bc)
= 1/2 * (2ab + 2ac + 2bc + a^2 + b^2 + c^2 - (a^2 + b^2 + c^2))
= 1/2 * ((a+b+c)^2 - (a^2 + b^2 + c^2))
That is:
int sum = 0;
int sum_sq = 0;
for (int i : arr) {
sum += i;
sum_sq += i*i;
}
int result = (sum*sum - sum_sq) / 2;
This is O(n) multiplications, instead of O(n^2). This'll certainly be better than the naive implementation at some point. Whether or not it's better for just 3 elements is something I haven't timed.
#chux's suggestion is essentially to redistribute operations:
ai * ai + 1 + ai * ai + 2 + ... + ai * an
-->
ai * (ai + 1 + ... + an)
combined with the avoiding unnecessary recomputation of partial sums of the (ai + 1 + ... + an) terms by leveraging the fact that each differs from the next by the value of one element of the input array.
Here's a one-pass implementation with O(1) overhead:
int psum(size_t n, int array[n]) {
int result = 0;
int rsum = array[n - 1];
for (int i = n - 2; i >= 0; i--) {
result += array[i] * rsum;
rsum += array[i];
}
return result;
}
The sum of all elements to the right of index i is maintained from iteration to iteration in variable rsum. It's unnecessary to track its various values in an array, because we need each value only for one iteration of the loop.
This scales linearly with the number of elements in the input array. You'll see that the number and type of operations is quite similar to #Barry's answer, but nothing analogous to his final step is required, which saves a few operations.
As #Barry observes in comments, the iteration can also be run in the other direction, in conjunction with tracking the left-hand partial sums intead of the right-hand ones. That would diverge a bit more from #chux's description, but it relies on exactly the same principles.
We have (a + b + c + ...)2 = (a2 + b2 + c2 + ...) + 2(ab + bc + ca + ...)
You want the sum S = ab + bc + ca + ..., which has O(n2) pairs (using 2 nested loops)
You can do 2 separated loops, one calculates P = a2 + b2 + c2 + ... in O(n) time, and another calculates Q = (a + b + c + ...)2 also in O(n) time. Then take S = (Q - P) / 2.
Make 1 pass, walk from the end of [a] to the front and form a sum of all the elements "to the right".
2nd pass, Multiple a[i] * sum[i].
O(n).
long sum0(int a[], int n) {
long sum = 0;
for (int i = 0; i < n - 1; ++i)
for (int k = i + 1; k < n; ++k)
sum += a[i] * a[k];
return sum;
}
long sum1(int a[], int n) {
int long sums[n];
sums[n - 1] = 0;
for (int i = n - 2; i >= 0; i--) {
sums[i] = a[i+1] + sums[i + 1];
}
long sum = 0;
for (int i = 0; i < n - 1; ++i)
sum += a[i] * sums[i];
return sum;
}
void test(int a[], int n) {
long s0 = sum0(a, n);
long s1 = sum1(a, n);
if (s0 != s1) printf("%9ld %9ld\n", s0, s1);
}
void tests(int k) {
while (k--) {
int n = rand() % 10 + 2;
int a[n + 1];
for (int m = 0; m < n; m++)
a[m] = rand() % 256;
test(a, n);
}
}
int main() {
int a[3] = { 7, 2, 1 };
printf("%d\n", sum1(a, 3));
tests(1000000);
puts("Done");
}
As it turns out the sums[] array is not needed either as the the running sums needs only 1 location. This effectively makes this answers similar to others
long sum1(int a[], int n) {
int long sums = 0;
long sum = 0;
for (int i = n - 2; i >= 0; i--) {
sums = a[i+1] + sums;
sum += a[i] * sums;
}
return sum;
}