T1:
problem:
给定n个给定长度的木棍,最多可以切maxcut刀,问最多形成多少个长度为10的个棍。
solution:
先从小到大处理长度为10的倍数的木棍,然后处理剩余的木棍,每次切出一个长度为10的木棍直到长度小于等于10。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
class Cut {
public:
int getMaximum(vector <int> eelLengths, int maxCuts) {
int n = eelLengths.size();
sort(eelLengths.begin(), eelLengths.end());
int ans = 0;
for (int i = 0; i < n; ++i)
if (eelLengths[i] % 10 == 0) {
while (maxCuts > 0 && eelLengths[i] > 10) {
--maxCuts;
eelLengths[i] -= 10;
++ans;
}
if (eelLengths[i] == 10) ++ans;
}
for (int i = 0; i < n; ++i) {
while (maxCuts > 0 && eelLengths[i] > 10) {
--maxCuts;
eelLengths[i] -= 10;
++ans;
}
}
return ans;
}
};
T2:
problem:
给定一个长度为n(n <= 40)的字符串S(只有‘x,'‘o’)。现要求有多少对集合<X,Y>满足:
X = {p1, p2, p3...., p[n / 2]}, p1 < p2 ...< p [n / 2]
Y = {q1, q2, q3,... q[n / 2]}, q1 < q2 ... < q[n / 2]
X 和 Y的并集为 {1, 2, 3, ..., n}
S[pi] = S[qi] .
solution:
如果 n <= 20,那么可以设 f[i][mask]代表处理完前 i 个字符,元素多的那个集合比少那个的多了mask的元素。如果第i + 1个字符等于mask里的第一个元素所代表的字符,那么可以转移到f[i + 1][mask - p] , p是mask里的第一个元素(相当于把第i + 1个字符加入元素少的集合),或者可以将第i + 1 个字符加入元素多的那个集合,即转移到 f[i + 1][mask + (i + 1)]。最后的f[n][0]即是答案。
这题的n <= 40, 那么可以将原串拆成两部分做,前半部分要求两个集合的前缀字符要相同,后半部分要求两个集合的后缀字符要相同。所以前半部分和前面的做法一样,而后半部分需要将串先翻转再做。然后就是合并两个串的结果,考虑到前半部分的结果f[n / 2][mask],代表元素多的集合多了mask,所以就要求后半部分要把多的这些填补上去。即对于所有满足mask1 的翻转等于mask的集合,将 f[n / 2][mask] * g[n / 2][mask1]计入答案(g是后半部分的结果)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int a[30], b[30];
LL dp[2][1 << 20];
LL f1[1 << 20], f2[1 << 20];
const int P = 40007;
map <ULL, LL> wayss;
inline void updata(LL &x, LL y) {
x += y;
}
inline void solve(int a[], int n, LL f[]) {
memset(dp, 0, sizeof(dp));
int cur = 0, nex = 1;
dp[0][0] = 1;
for (int i = 0; i < n; ++i) {
memset(dp[nex], 0, sizeof(dp[nex]));
for (int mask = 0; mask < 1 << n; ++mask) {
if (!dp[cur][mask]) continue;
if (mask == 0) updata(dp[nex][1 << i], dp[cur][mask] * 2);
else {
int lowbit = mask & -mask;
int j = __builtin_ctz(lowbit);
if (a[j] == a[i]) updata(dp[nex][mask ^ lowbit], dp[cur][mask]);
updata(dp[nex][mask | (1 << i)], dp[cur][mask]);
}
}
swap(cur, nex);
}
memcpy(f, dp[cur], sizeof(dp[cur]));
}
class SPartition {
public:
LL getCount(string s) {
int n = s.size(), m = n / 2;
for (int i = 0; i < m; ++i)
a[i] = (s[i] == 'o');
for (int i = 0; i < m; ++i)
b[i] = (s[n - i - 1] == 'o');
solve(a, m, f1);
solve(b, m, f2);
for (int i = 0; i < 1 << m; ++i)
f2[i] /= 2;
LL ans = f1[0] * f2[0] * 2;
for (int mask = 1; mask < 1 << m; ++mask)
if (f2[mask]) {
ULL sum = 0;
for (int i = m - 1; i >= 0; --i)
if (mask >> i & 1) sum = sum * P + b[i] + 10;
wayss[sum] += f2[mask];
}
for (int mask = 1; mask < 1 << m; ++mask)
if (f1[mask]) {
ULL sum = 0;
for (int i = 0; i < m; ++i)
if (mask >> i & 1) sum = sum * P + a[i] + 10;
ans += f1[mask] * wayss[sum];
}
return ans;
}
};