最大公倍数
描述
小栖有一个区间,他准备从中取三个数,他想知道如何取才能使得它们的最小公倍数最大 请直接告诉小栖最小公倍数是多少。
思路:
感觉很有意思的一道题。
可以想到,如果找的三个数有公约数,那么至少是成倍的下降。
显然的结论是,x和x+1互质。如果x是奇数,x和x+2互质。
那么可以想到肯定是从区间末尾抽出三个互质的数相乘结果更优。
如果
,那么只能是这三个数没得选了。
如果
,且
为奇数,那就直接取
,这三个数肯定互质。
如果
,且
为偶数,且为3的倍数,那么
和
有公约数,所以你只能取
如果
,且
为偶数,且不为3的倍数,那么有几种取法:
。很明显最优就是取
。
typedef long long ll;
class Solution {
public:
/**
* @param a: Left margin
* @param b: Right margin
* @return: return the greatest common multiple
*/
ll gcd(ll n,ll m) {
return m == 0 ? n : gcd(m,n % m);
}
ll lcm(ll n, ll m) {
return n * m / gcd(n,m);
}
long long greatestcommonmultiple(int a, int b) {
ll A = a,B = b;
if(B - A == 2) {
return lcm(A,lcm(A + 1,A + 2));
}
if(B & 1) return B * (B - 1) * (B - 2);
else {
if(B % 3 == 0) {
return (B - 1) * (B - 2) * (B - 3);
} else {
return B * (B - 1) * (B - 3);
}
}
return -1;
}
};
完美字符串
描述
定义若一个字符串的每个字符均为’1’,则该字符串称为完美字符串。给定一个只由’0’和’1’组成的字符串s和一个整数k。你可以对字符串进行任意次以下操作
选择字符串的一个区间长度不超过k的区间[l, r],将区间内的所有’0’修改成’1’,将区间内所有的’1’修改成’0’。
你最少需要多少次操作,可以将字符串s修改成一个完美字符串
思路:
可以想到肯定是修改全为0的区间最优,否则你修改到了1的部分,到时候还得再抵消这部分操作。
class Solution {
public:
/**
* @param s: string need to be transformed
* @param k: minimum char can be transformed in one operation
* @return: minimum times of transforming all char into '1'
*/
int perfectString(string &s, int k) {
// Write your code here.
int n = s.size();
int cnt = 0;
int ans = 0;
for(int i = 0;i < n;i++) {
if(s[i] == '0') {
cnt++;
} else {
ans += cnt / k;
if(cnt % k) ans++;
cnt = 0;
}
}
ans += cnt / k;
if(cnt % k) ans++;
return ans;
}
};
字符串游戏
描述
Alice与Bob在一起玩一个游戏。现在有一个字符串s,每个人可以选择字符串中的某一个区间和一种字符,删除这个区间内的所有该字符(需要删除字符的数量至少为1)。从Alice开始,Alice与Bob轮流进行进行这个操作,若在某个玩家删除前,字符串已经为空,则该玩家获胜。
假设Alice和Bob都会按照其最优的解法删除,Alice想知道,她是否可以获胜。
思路:
结论题,没啥意思。就是个反nim博弈
int sum[100005][30];
class Solution {
public:
/**
* @param s: a string for this game
* @return: return whether Alice can win this game
*/
bool stringGame(string &s) {
// Write your code here.
memset(sum,0,sizeof(sum));
int n = s.size();
for(int i = 0;i < n;i++) {
for(int j = 0;j < 26;j++) {
sum[i + 1][j] = sum[i][j];
}
sum[i + 1][s[i] - 'a']++;
}
int ans = 0;
int cnt1 = 0,cnt2 = 0;
for(int i = 0;i < 26;i++) {
ans ^= sum[n][i];
if(sum[n][i] == 1) cnt1++;
if(sum[n][i] >= 2) cnt2++;
}
if(ans != 0 && cnt2) return true;
if(ans == 0 && cnt2 == 0) return true;
return false;
}
};
房屋染色
描述
有n个房子在一列直线上,现在Bob需要给房屋染色,共有k种颜色。每个房屋染不同的颜色费用也不同,Bob希望有一种染色方案使得相邻的房屋颜色不同。但Bob计算了使相邻房屋颜色不同的最小染色费用,发现花费非常高。 于是Bob想选择一个区间作为主题步行街,在这个区间中的所有房子必须染成同一个颜色。Bob觉得这样可能能降低总花费,但是也不想让这个步行街太长。Bob认为步行街的长度最多为’t’。但这个花费太难计算,Bob打算交给你来计算。你能算出将这些房子进行染色的最小花费是多少吗?
费用通过一个nxk 的矩阵给出,比如costs[0][0]表示房屋0染颜色0的费用,costs[1][2]表示房屋1染颜色2的费用。 t是一个整数,表示有最多有多少个房屋颜色相同。
房子总数: 1 <= n <= 100 颜色总数: 1 <= k <= 100 步行街长度上限: 1 <= t <= 10 房屋染色费用: 1 <= cost[i][j] <= 1000
思路:
可以想到,花费与你选了哪些房子作为步行街,这个步行街长度,当前房子颜色有关。所以以此为状态。
定义 代表选到了第 个房子,当前房子颜色为 ,该房子与之前房子颜色相同连续多少个,前 个房子是否用了步行街。
转移的话就是枚举当前房子颜色和之前房子颜色,枚举前一个房子连续颜色长度。
如果当前房子和之前房子颜色相同,那就可以连成一个步行街。
之所以要加第四维状态(是否用了步行街),是因为步行街只能用一个,所以如果之前房子颜色相同长度只有一个,且要把当前房子和之前房子连起来,那么条件是之前房子之前没有出现过步行街。
const int INF = 0x3f3f3f3f;
class Solution {
public:
/**
* @param costs: costs of paint ith house into color j
* @param t: maximum length of street
* @return: minimum costs of painting all houses
*/
int dp[105][105][15][2];
int paintHouseIII(vector<vector<int>> &costs, int t) {
// Write your code here.
memset(dp,INF,sizeof(dp));
int n = costs.size();
int k = costs[0].size();
for(int i = 0;i < k;i++) dp[0][i][1][0] = 0;
for(int i = 0;i < n;i++) {
for(int pre = 0;pre < k;pre++) { //上一个房子的颜色
for(int now = 0;now < k;now++) { //当前房子的颜色
for(int len = 1;len <= t;len++) { //当前房子连续的长度
if(pre == now) { //叠加
if(len == 1) {
dp[i + 1][now][len + 1][1] = min(dp[i + 1][now][len + 1][1],dp[i][pre][len][0] + costs[i][now]);
} else {
dp[i+1][now][len + 1][1] = min(dp[i+1][now][len + 1][1],dp[i][pre][len][1] + costs[i][now]);
}
} else { //不叠加
dp[i + 1][now][1][1] = min(dp[i+1][now][1][1],dp[i][pre][len][1]+costs[i][now]);
dp[i + 1][now][1][0] = min(dp[i + 1][now][1][0],dp[i][pre][len][0]+costs[i][now]);
}
}
}
}
}
int ans = INF;
for(int i = 0;i < k;i++) {
for(int j = 1;j <= t;j++) {
ans = min(ans,min(dp[n][i][j][0],dp[n][i][j][1]));
}
}
return ans;
}
};