SRM565 DIV2

http://community.topcoder.com/stat?c=round_overview&er=5&rd=15187

250-point problem

Problem Statement

 A histogram of a given collection of numbers graphically represents the frequency of each value in the collection. We are given several numbers ranging from 0 to 9 as a vector <int>values. The goal is to build their histogram according to the following rules.

1) The width of the histogram should be exactly 10.

2) The height of the histogram should equal to H+1, where H is the number of times the most frequent element occurs invalues.

3) The i-th (0-based) column of the histogram corresponds to the value i. Let X(i) be the frequency of value i invalues. Then the last X(i) characters in the column should be 'X's and the other ones should be '.'s. For example, if value i was not present invalues, the column should be filled with '.' characters. If i was present once, the last element of the column should be 'X' and and the other ones should be '.'s. If i was present twice, the last two elements should be 'X's and and the other ones should be '.'s, and so on.

Build the histogram and return it as a vector <string>.

Definition

 
Class:ValueHistogram
Method:build
Parameters:vector <int>
Returns:vector <string>
Method signature:vector <string> build(vector <int> values)
(be sure your method is public)
 
 

Constraints

-values will contain between 1 and 50 elements, inclusive.
-Each element of values will be between 0 and 9, inclusive.

Examples

0) 
 
{2, 3, 5, 5, 5, 2, 0, 8}
Returns: {"..........", ".....X....", "..X..X....", "X.XX.X..X." }
The most frequent value is 5, which occurs 3 times. Hence the height of the histogram is 4. It looks as follows:
..........
.....X....
..X..X....
X.XX.X..X.
1) 
 
{9, 9, 9, 9}
Returns: {"..........", ".........X", ".........X", ".........X", ".........X" }
..........
.........X
.........X
.........X
.........X
2) 
 
{6, 4, 0, 0, 3, 9, 8, 8}
Returns: {"..........", "X.......X.", "X..XX.X.XX" }
..........
X.......X.
X..XX.X.XX
3) 
 
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Returns: {"..........", "XXXXXXXXXX" }
..........
XXXXXXXXXX
4) 
 
{6, 2, 3, 3, 3, 7, 8, 1, 0, 9, 2, 2, 4, 3}
Returns: {"..........", "...X......", "..XX......", "..XX......", "XXXXX.XXXX" }
..........
...X......
..XX......
..XX......
XXXXX.XXXX

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

class ValueHistogram
{
public:
	vector<string> build(vector<int> values)
	{
		int cnt[10]={},maxcnt=0;
		for(int i=0;i<values.size();++i)
			cnt[values[i]]++;
		for(int i=0;i<10;++i)
			maxcnt=max(maxcnt,cnt[i]);
		vector<string> res;
		res.push_back("..........");
		for(int i=maxcnt;i>0;--i)
		{
			string str="..........";
			for(int j=0;j<10;++j)
				if(cnt[j]>=i)
					str[j]='X';
			res.push_back(str);
		}
		return res;
	}
};

int main()
{
	vector<int> a;
	int cnt=4,b[]={9,9,9,9};
	for(int i=0;i<cnt;++i)
		a.push_back(b[i]);
	ValueHistogram v;
	vector<string> c=v.build(a);
	for(int i=0;i<c.size();++i)
		cout<<c[i]<<endl;
	system("pause");
	return 0;
}






500-point problem

Problem Statement

 Manao is traversing a valley inhabited by monsters. During his journey, he will encounter several monsters one by one. The scariness of each monster is a positive integer. Some monsters may be scarier than others. The i-th (0-based index) monster Manao will meet has scariness equal to dread[i].

Manao is not going to fight the monsters. Instead, he will bribe some of them and make them join him. To bribe the i-th monster, Manao needsprice[i] gold coins. The monsters are not too greedy, therefore each value inprice will be either 1 or 2.

At the beginning, Manao travels alone. Each time he meets a monster, he first has the option to bribe it, and then the monster may decide to attack him. A monster will attack Manao if and only if he did not bribe it and its scariness is strictly greater than the total scariness of all monsters in Manao's party. In other words, whenever Manao encounters a monster that would attack him, he has to bribe it. If he encounters a monster that would not attack him, he may either bribe it, or simply walk past the monster.



Consider this example: Manao is traversing the valley inhabited by the Dragon, the Hydra and the Killer Rabbit. When he encounters the Dragon, he has no choice but to bribe him, spending 1 gold coin (in each test case, Manao has to bribe the first monster he meets, because when he travels alone, the total scariness of monsters in his party is zero). When they come by the Hydra, Manao can either pass or bribe her. In the end, he needs to get past the Killer Rabbit. If Manao bribed the Hydra, the total scariness of his party exceeds the Rabbit's, so they will pass. Otherwise, the Rabbit has to be bribed for two gold coins. Therefore, the optimal choice is to bribe the Hydra and then to walk past the Killer Rabbit. The total cost of getting through the valley this way is 2 gold coins.

You are given the vector <int>s dread and price. Compute the minimum price Manao will pay to safely pass the valley.

Definition

 
Class:MonstersValley2
Method:minimumPrice
Parameters:vector <int>, vector <int>
Returns:int
Method signature:int minimumPrice(vector <int> dread, vector <int> price)
(be sure your method is public)
 
 

Constraints

-dread will contain between 1 and 20 elements, inclusive.
-Each element of dread will be between 1 and 2,000,000,000, inclusive.
-price will contain between the same number of elements as dread.
-Each element of price will be either 1 or 2.

Examples

0) 
 
{8, 5, 10}
{1, 1, 2}
Returns: 2
The example from the problem statement.
1) 
 
{1, 2, 4, 1000000000}
{1, 1, 1, 2}
Returns: 5
Manao has to bribe all monsters in the valley.
2) 
 
{200, 107, 105, 206, 307, 400}
{1, 2, 1, 1, 1, 2}
Returns: 2
Manao can bribe monsters 0 and 3.
3) 
 
{5216, 12512, 613, 1256, 66, 17202, 30000, 23512, 2125, 33333}
{2, 2, 1, 1, 1, 1, 2, 1, 2, 1}
Returns: 5
Bribing monsters 0, 1 and 5 is sufficient to pass safely.

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

class MonstersValley2
{
public:
	int minimumPrice(vector<int> dread, vector <int> price)
	{
		long long dp[50][101]={0}; // dp[i][j]: max scariness got after passing i-th monster and spending j gold coins
		for(int j=0; j<=100; ++j)
			if(j < price[0])
				dp[0][j] = 0;
			else
				dp[0][j] = dread[0];
		int n = dread.size();
		int prev = price[0];
		for(int i=1; i<n; ++i)
		{
			for(int j=prev; j<=100; ++j)
			{
				dp[i][j] = dp[i-1][j];
				if(j>=prev+price[i] && dp[i][j]<dp[i-1][j-price[i]]+dread[i])
					dp[i][j] = dp[i-1][j-price[i]] + dread[i];
			}
			for(int j=0; j<=100; ++j)
				if(dp[i][j] >= dread[i])
				{
					prev = j;
					break;
				}
		}
		return prev;
	}
};

int main()
{
	MonstersValley sol;
	long long d[]={8, 5, 10};
	int p[]={1, 1, 2};
	vector<long long> dread(d, d+sizeof(d)/sizeof(long long));
	vector<int> price(p, p+sizeof(p)/sizeof(int));
	printf("%d\n", sol.minimumPrice(dread, price));
	system("pause");
	return 0;
}






1000-point problem

Problem Statement

 A divisible sequence with starting value N and lengthH is a sequence of positive integers with the following properties:
  • The sequence has H elements, labeled A[0] through A[H-1].
  • A[0] equals N.
  • For each i between 0 and H-2, inclusive, A[i+1] divides A[i].
You are given the ints N and H. Let C be the count of all divisible sequences with starting valueN and lengthH. Return the value (C modulo 1,000,000,009).

Definition

 
Class:DivisibleSequence
Method:count
Parameters:int, int
Returns:int
Method signature:int count(int N, int H)
(be sure your method is public)
 
 

Constraints

-N will be between 1 and 1,000,000,000, inclusive.
-H will be between 1 and 1,000,000,000, inclusive.

Examples

0) 
 
5
3
Returns: 3
The three possible sequences are:
5, 5, 5
5, 5, 1
5, 1, 1
1) 
 
6
3
Returns: 9
The nine possible sequences are:
6, 6, 6
6, 6, 3
6, 6, 2
6, 6, 1
6, 3, 3
6, 3, 1
6, 2, 2
6, 2, 1
6, 1, 1
2) 
 
10
2
Returns: 4
A[1] can be equal to each of the divisors of the number 10. That is, A[1] can be 1, 2, 5, or 10.
3) 
 
1
10000
Returns: 1
The only possible sequence consists of all ones.
4) 
 
30
4
Returns: 64
5) 
 
25883
100000
Returns: 991000009

#include <cstdio>
#include <set>
#include <map>

using namespace std;

class DivisibleSequence
{
	map<pair<int,int>, int> memo;
	int calc(int n, int h)
	{
		if(h == 1)
			return 1;
		else if(memo.find(make_pair(n,h))!=memo.end())
			return memo[make_pair(n,h)];
		set<int> div;
		for(int i=1; i*i<=n; ++i)
			if(n%i==0)
			{
				div.insert(i);
				div.insert(n/i);
			}
		int cnt=0;
		for(set<int>::iterator i=div.begin(); i!=div.end(); ++i)
			cnt=(cnt + calc(*i, h-1)) % 1000000009;
		memo[make_pair(n,h)]=cnt;
		return cnt;
	}
public:
	int count(int N, int H)
	{
		return calc(N,H);
	}
};

int main()
{
	DivisibleSequence sol;
	printf("%d\n", sol.count(25883, 100));
	system("pause");
	return 0;
}

the above solution fails 2 (out of the fist 14) test cases in practical system test, because the memo uses too much memory. Actually it does not even pass the last example given.

Problem: 1000
Test Case: 5
Succeeded: No
Execution Time: 0 ms
Args:
{25883, 100000}

Expected:
991000009

Received:
segmentation fault

Problem: 1000
Test Case: 9
Succeeded: No
Execution Time: 0 ms
Args:
{1000000000, 1000000000}

Expected:
1

Received:
segmentation fault


correct solutions: http://apps.topcoder.com/wiki/display/tc/SRM+565

class DivisibleSequence
{
	static const int MOD = 1000000009;
	int modPow(int x, int y)
	{
		int r = 1, a = x;
		while(y > 0)
		{
			if((y&1) == 1)
				r = r * (long long)a % MOD;
			a = a * (long long)a % MOD;
			y /= 2;
		}
		return r;
	}
	int modInv(int x)
	{
		return modPow(x, MOD-2);
	}
	int modDiv(int p, int q)
	{
		return p * (long long)modInv(q) % MOD;
	}
	int C(int n, int k)
	{
		if(k > n)
			return 0;
		int p = 1, q = 1;
		for(int i=1; i<=k; ++i)
		{
			q = q * (long long)i % MOD;
			p = p * (long long)(n-i+1) % MOD;
		}
		return modDiv(p, q);
	}
public:
	int count(int N, int H)
	{
		int res = 1;
		for(int p=2; p<=N/p; ++p)
		{
			int c = 0;
			while(N % p == 0)
			{
				N /= p;
				c++;
			}
			res = res * (long long)C(H-1+c, c) % MOD;
		}
		if(N > 1)
			res = res * (long long)H % MOD;
		return res;
	}
};

Explanation:

DivisibleSequence rate it discuss it 
Used as: Division Two - Level Three:

Value 1000
Submission Rate 38 / 1043 (3.64%)
Success Rate 7 / 38 (18.42%)
High Score sandytea for 941.63 points (7 mins 9 secs)
Average Score 509.57 (for 7 correct submissions)

Factorize

Since the problem is about integer division, it is useful to see n as a product of its prime factors. For example, n = 12 = 2*2*3 = 22*3.

When the statement asks us that the i-th number in the sequence must be a divisor of the (i-1)-th one, we can see it as having a subset of the prime factors. 2*2*3, 2*3, 3, 2*2, 2 and 1 are all divisors of 2*2*3. (Note that 1 acts as an empty subset).

Independence

Let us define a number as the product of all prime numbers each raised to an exponent. 12 = 22 * 31 * 50 * 70 * .... Then for another number to be a divisor, each of the prime factors must have an exponent less than or equal to the exponent for the same prime in the first number.

This new way to see the problem is useful in that it shows that the ways the prime factors change are independent of each other. For example, picking to decrease the exponent of 3 in the product will not affect our options to decrease the exponent of 2. Then we have that the decisions made for each prime factor are independent events. In order to count the number of ways for a combination of independent events to occur, we can just calculate the number of ways for each specific event and then multiply them all.

This means that, given a number like 12 = 22 * 31, we can count the number of ways to decrease exponent 2 and the number of ways to decrease exponent 1 over the H slots and then multiply each other. For H=3

n = 2*2                     n = 3
1) 2*2, 2*2, 2*2            1) 3, 3, 3               
2) 2*2, 2*2,   2            2) 3, 3, 1
3) 2*2, 2*2,   1            3) 3, 1, 1
4) 2*2,   2,   2
5) 2*2,   2,   1
6) 2*2,   1,   1

There are 6 ways to decrease the exponent of prime factor 2 (2) over the H=3 sequence positions and 3 ways for the exponent of prime factor 3 (1). The product is 3*6 = 18. There should be 18 ways in total to have divisible sequences for n = 12. This is indeed true:

x 3,3,3 3,3,1 3,1,1
4,4,4 12,12,12 12,12,4 12,4,4
4,4,2 12,12,6 12,12,2 12,4,2
4,4,1 12,12,3 12,12,1 12,4,1
4,2,2 12,6,6 12,6,2 12,2,2
4,2,1 12,6,3 12,6,1 12,2,1
4,1,1 12,3,3 12,3,1 12,1,1

The table shows the 18 divisor sequences for n=12 and H=18, and how the 6 ways to decrease the exponent of prime factor 2 and the 3 ways to decrease the exponent for prime factor 3 combine together to make them.

For each prime factor

What is left is to solve this sub-problem: For each prime factor, we find the exponent c of the factor in n. How many sequences of H non-negative elements begin with sequence[0] = c and follow the rule: (sequence[i] <= sequence[i-1]) ? Note that H can be as large as 109. For example, for 12=2*2*3, the exponent of 2 begins as c=2, and it can become 1 or 0 eventually: {2,0,0}, {2,1,0}, {2,1,1}, {2,2,0}, {2,2,1}, {2,2,2}. To solve this problem, note that the first element must be c, when selecting the next H-1 elements, we repeat the following choice:

  • Decrease current number by 1.
  • or
  • Select the current number for the next position.

Note that the option to decrease the number can be repeated consecutive times.

For example, consider the sequence {4, 4, 2, 2, 1} for c=4, and H=4. The first element is always c. For the remaining H-1 positions: We first choose the current number of position i=1 (4). Then we decrease (3). Decrease again (2). Choose current number (2) for position i=2. Choose current number (2) again for position i=3. Decrease (1). Finally, choose current number (1) for position i=4.

Note that we must do choose operations exactly H-1 times and we can decrease at most c times before the last {choose} operation. We can consider the problem as having H-1 show operations, c decrease operations and we just need to decide the order. Of H-1+c operations, we need to pick which ones will be decrease operations. This is the same as saying C(H-1+c, c). If we represent decrease operations as * and show operations as S, the following shows the three different representations of each of the 6 different exponents based on the prime factor 2 for n=12 = 2*2*3, H=3:

**SS      {2,0,0}      2*2,   1,   1      4,1,1   
*S*S      {2,1,0}      2*2,   2,   1      4,2,1
*SS*  ->  {2,1,1}  ->  2*2,   2,   2  ->  4,2,2
S**S      {2,2,0}      2*2, 2*2,   1      4,4,1
S*S*      {2,2,1}      2*2, 2*2,   2      4,4,2
SS**      {2,2,2}      2*2, 2*2, 2*2      4,4,4

The last bit of complication is to calculate the binomial coefficient.

How to calculate C(n, k) when n is possibly very large

The kind of binomial coefficients we need are in the form C(H-1+c, c), while H can be very large, c is at most 16 (The maximum number of prime factors for N. We just need a way to calculate the binomial coefficient in this case. The following is a O(k) method to calculate C(n,k):

C(n,k) = n! / ( k! * (n-k)! )

C(n,k) = (n! / (n-k)! ) / k!

(n! / (n-k)! ) = n*(n-1)*(n-2)*...(n-k+1)*(n-k)! / (n-k)!

(n! / (n-k)! ) = n*(n-1)*(n-2)*...(n-k+1)

Since (n! / (n-k)! ) and k! can be calculated in O(k) time, all that is left is a division of the two. Note that per the problem statement we do all operations modulo 1000000009. A large prime number. In order to do modular division, we actually need to find the modular multiplicative inverse of k!. Thanks to 1000000009 being a prime number, we can use Fermat's little theorem to calculate this inverse.

Extracting a list of prime factors

Note that n is at most 1000000000. A O(sqrt(n)) approach like the improved trial division will be good enough.

final int MOD = 1000000009;
// Calculates x raised to the y-th power modulo MOD
long modPow(long x, long y)
{
    long r=1, a=x;
    while (y > 0) {
        if ( (y&1)==1 ) {
            r = (r * a) % MOD;
        }
        a = (a * a) % MOD;
        y /= 2;
    }
    
    return r;
}
// Modular multiplicative inverse through Fermat's little theorem:
long modInverse(long x)
{
    return modPow(x, MOD-2);
}
// Modular division x / y, find modular multiplicative inverse of y
// and multiply by x.
long modDivision(long p, long q)
{
    return (p * modInverse(q)) % MOD;
}
// Binomial coifficient C(n,k) in O(k) time.
long C(long n, int k)
{
    if (k > n) {
        return 0;
    }
    long p = 1, q = 1;
    for (int i=1; i<=k; i++) {
        q = ( q * i) % MOD;
        p = ( p * (n - i + 1) ) % MOD;
    }
    return modDivision( p, q);
}
public int count(int N, int H)
{
    long res = 1;
    // Let us use trial divison to find prime factors p
    for (int p=2; p <= N/p; p++) {
        int c = 0;
        while (N % p == 0) {
            N /= p;	
            c++;
        }
        res = ( res * C(H-1+c, c) ) % MOD;
    }

    if (N > 1) {
        // N is one last prime factor, c = 1
        // C(H-1+1,1) = H
        res = ( res * H ) % MOD;
    }
    return (int)res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值