Pages

Saturday, November 20, 2010

SPOJ (Ambitious Manager)

This is an interesting math problem.

For the solution, you just have to observe and prove that, bi > bi-1 + bi-2+ ... + b1 for all i > 1. The question is, how one might observe this fact. That's when 'numerical experimentation' can help you. Just write down some (say, 10) random values of ai on paper and calculate the corresponding values of bi and you will see it.

This can be proved with induction.

For the base case, note that, b2 > b1 because, b2 = a2 + 2*a1 = a2 + 2*b1. (ai > 0 for all i)

In fact, from the definition of bi it is clear that,
bi = ai + 2*bi-1.

Now, lets assume that, bn-1 > bn-2+ ... + b1 for some n > 2
bn = ai + 2*bi-1
therefore, bn > ai + 2*(bi-2+ ... + b1) (by the induction hypothesis)

This poof leads to the following conclusion:
Let, bi be the maximum number such that bi ≤ N. We must take this value, otherwise it will be impossible to build N from the rest of the values.

So, you have to take the maximum bi not exceeding N and replace N with N-bi, as long as it is possible. If, you reach 0, you are done. Just print the positions of the taken numbers. Otherwise print a -1.

Note that, there will never be multiple solutions.
In fact, for any sequence S of integers such that, Si > Si-1 + Si-2 + ... + S1. Every subset of S yields a different sum.

To see this, consider two different subsets A and B. Without loss of generality, assume that, sum(A) ≥ sum(B), where, sum(X) is the sum of the elements of subset X. Let, k be the largest index such that, Sk is included in A but not in B. According to the proof described above, Sk will always be greater than the sum of all Si, where k > i and Si is included in B. So, sum(A) != sum(B) (i.e. A > B)


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<ctype.h>

#include<vector>
#include<set>
#include<map>
#include<string>
#include<stack>
#include<queue>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;
typedef pair<int,int> pii;

#define FOR(A,B) for(int A = 0; A < (B); ++A)
#define REP(A,B,C) for(int A = (B); A <= (C); ++A)
#define CLR(X,Y) memset(X,(Y),sizeof(X))


int main()
{
   LL a[55], b[55];
   int T; scanf("%d",&T);
  
   while(T--)
   {
       LL n;
       int k; cin>>n>>k;
              
       FOR(i,k)
       {
           cin>>a[i];
          
           if(i==0) b[i] = a[i];
           else b[i] = (b[i-1]<<1)+a[i];
       }   
              
       vector<int> ans;
      
       for(int i = k-1; i >= 0; --i)
       {
           if(b[i]<=n)
           {
               ans.push_back(i+1);
               n -= b[i];  
           }  
       }
      
       if(n > 0)
       {
           puts("-1");  
       }
       else
       {           
           for(int i = ans.size()-1; i >= 0; --i)
           if(i<ans.size()-1) printf(" %d",ans[i]);
           else printf("%d",ans[i]);
          
           puts("");  
       }
   }
  
   return 0;
}


this blog is inspired by: http://one-problem-a-day.blogspot.com

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Nice proof, do you have more problems that require similar solutions to try them by myself ?

    ReplyDelete
  3. you can try problem 4855 from here:
    http://acm.uva.es/archive/nuevoportal/region.php?r=as9&year=2010

    ReplyDelete