TOPCODER SRM 612 DIV2

来源:互联网 发布:激光美容知乎 编辑:程序博客网 时间:2024/05/03 14:58

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>//dfsclass 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;//pasteprintf("%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;//copyprintf("%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,2i 的数有多少个。然后最开始我写了一个暴搜的方法,即对于每一个i枚举选择的个数,这个方法复杂度较高,对大数据超时了。注意到每个数都是2的幂,因此如果在组成某一个和的过程中,选择了k个2i,k是偶数,那么它等价于选择了k/2个2i+1 ,比方说数据集合是{2,2,2,4},那么他们组成的和的个数与{2,4,4}的个数是等价的。因此对于2i,有两种选择策略:(1)如果选择偶数个(k),则等价于选择了k/2个2i+1 。(2)如果选择了奇数个(k),则等价于选择了1个2i,(k-1)/2个2i+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 50class 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);//evenif(x_k > 0)res += f(k + 1, (x_k - 1) / 2);//oddcnt[k][b] = res;}return res;}private:int v[MAX_POWER + 10];long long cnt[MAX_POWER + 10][MAX_CNT];/* data */};


0 0