250:统计串中‘RL’的数目即可。
#include <string>
class LeftAndRightHandedDiv2
{
public:
int count(string S)
{
int n = 0;
for(int i = 0; i < S.length - 1; i++)
{
if(S[i] == 'R' && S[i + 1] == 'L')
n++;
}
return n;
}
/* data */
};
500:每次要么做复制操作,要么做粘贴操作。
第一种解法:枚举每次是复制,还是粘贴,搜索所有的情况。每次搜索需记录下当前所花的步数、已打出的笑脸的个数、复制板上笑脸的个数。
#include "stdio.h"
#include <memory.h>
//dfs
class EmotionDiv2
{
public:
int printSmiles(int smiles)
{
s = smiles;
result = 10000;
dfs(0, 1, 0);
return result;
}
private:
void dfs(int step, int count, int copy)
{
if(count > s)
return;
if(count == s)
{
if(step < result)
result = step;
// printf("%d\n", result);
return;
}
if(copy < count)
{
dfs(step + 1, count, count); //copy
}
if(copy != 0)
{
dfs(step + 1, count + copy, copy); //paste
}
}
private:
int result;
int s;
/* data */
};
第二种解法:这是一个每步做出选择的最优化问题,可考虑使用dp求解。
定义dp[i][j],表示打出i个笑脸,复制板上有j个笑脸时所需的最小步数。初始情况dp[1][0] = 0。由于只有copy、paste两种操作,因此到达dp[i][j]状态要么是采用了copy操作,要么是paste操作。(1)paste操作,dp[i][j] 只能从dp[i-j][j] + 1转移而来,因为复制板上笑脸个数是j个。(2)copy操作,在这种情况下,必有i == j,且此状态从dp[i][k] + 1转移而来,k <= i。
class EmotionDiv2
{
public:
int printSmiles(int smiles)
{
init();
printf("hello\n");
dp[1][0] = 0;
for(int i = 1; i <= smiles; i++)
{
for(int j = 1; j <= i; j++)
{
if(dp[i - j][j] + 1 < dp[i][j])
{
dp[i][j] = dp[i - j][j] + 1; //paste
printf("%d %d:%d\n", i, j, dp[i][j]);
}
if(i == j)
{
for(int k = 0; k <= i; k++)
{
if(dp[i][k] + 1 < dp[i][j])
{
dp[i][j] = dp[i][k] + 1; //copy
printf("%d %d:%d\n", i, j, dp[i][j]);
}
}
}
}
}
int result = 10000;
for(int i = 0; i <= smiles; i++)
{
if(dp[smiles][i] < result)
result = dp[smiles][i];
}
return result;
}
private:
void init()
{
for(int i = 0; i < 1010; i++)
{
for(int j = 0; j < 1010; j++)
{
dp[i][j] = 10000;
}
}
}
/* data */
private:
short dp[1010][1010];
};
1000:先统计对于不同的i,2
i 的数有多少个。然后最开始我写了一个暴搜的方法,即对于每一个i枚举选择的个数,这个方法复杂度较高,对大数据超时了。注意到每个数都是2的幂,因此如果在组成某一个和的过程中,选择了k个2
i ,k是偶数,那么它等价于选择了k/2个2
i+1 ,比方说数据集合是{2,2,2,4},那么他们组成的和的个数与{2,4,4}的个数是等价的。因此对于2
i ,有两种选择策略:(1)如果选择偶数个(k),则等价于选择了k/2个2
i+1 。(2)如果选择了奇数个(k),则等价于选择了1个2
i ,(k-1)/2个2
i+1 。
而选择偶数个2i 造成的结果是所得到的和的二进制串的第i位是0,选择奇数个则是该位是1。因此本问题可以对得到的和的每一位进行枚举:对于第i位,如果有K个2i ,如果该位是0,那么可以转化为k/2个2i+1 。如果该位是1,那么可以保留1个2i ,得到(k-1)/2个2i+1 。那么假如枚举到第k位,那么k位以下的那些位都是已经确定的,因此若2k 的数目是0,那么向上转化的过程就结束了,返回1即可,因为这和的每一位都已经确定了。得到如下递归程序。
#include <vector>
#include <map>
#include <set>
#include <stdio.h>
#include <iostream>
#include <memory.h>
#include <algorithm>
using namespace std;
#define MAX_POWER 50
#define MAX_CNT 50
class PowersOfTwo
{
public:
PowersOfTwo(){}
~PowersOfTwo(){}
long long count(vector<long long> powers)
{
for(unsigned int i = 0; i <= MAX_POWER; i++)
{
v[i] = std::count(powers.begin(), powers.end(), 1ll << i);
// cout << i << " " << v[i] << ",";
}
memset(cnt, -1, sizeof(cnt));
return f(0, 0);
}
private:
long long f(int k, int b)
{
if(k == MAX_POWER + 10)
return 1;
long long res = cnt[k][b];
if(res == -1)
{
res = 0;
int x_k = v[k] + b;
res += f(k + 1, x_k / 2); //even
if(x_k > 0)
res += f(k + 1, (x_k - 1) / 2); //odd
cnt[k][b] = res;
}
return res;
}
private:
int v[MAX_POWER + 10];
long long cnt[MAX_POWER + 10][MAX_CNT];
/* data */
};