将 n n 按照二进制拆位,不难发现相邻的两个 1 1 会对答案产生 1 1 的贡献,之后就将它们消去了。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
int n;
Read(n);
printf("%d\n", __builtin_popcount(n) >> 1);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
显然贪心就行了,需要注意的是不能存下每个数,但是存每个数被乘了几次就行了。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 100005;
int n, a[N], f[N];
LL ans;
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n);
for (int i = 0; i < n; ++i) {
Read(a[i]);
}
for (int i = 1; i < n; ++i) {
if (!a[i] && a[i - 1]) {
puts("-1");
return 0;
}
if (a[i] > a[i - 1]) {
if (a[i - 1]) {
for (; a[i - 1] << 1 <= a[i]; a[i - 1] <<= 1, --f[i]);
}
} else {
for (int t = a[i]; t < a[i - 1]; t <<= 1, ++f[i]);
}
ans += f[i] = max(0, f[i] + f[i - 1]);
}
printf("%lld\n", ans);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
因为任意两个主教不能攻击,所以一个格子最多被两个主教覆盖,用 n(2h−2) n ( 2 h − 2 ) 减去被两个主教都覆盖的格子数就是答案,二维数点即可。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
vector a[2], b[2];
int n, m;
LL ans;
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m), ans = 1LL * ((m << 1) - 1) * n;
for (int i = 1, x, y; i <= n; ++i) {
Read(x), Read(y);
a[x + y & 1].pb(x - y);
b[x + y & 1].pb(x + y);
}
for (int i = 0; i < 2; ++i) {
sort(b[i].begin(), b[i].end());
}
for (int i = 0; i < 2; ++i) {
for (auto x : a[i]) {
ans -= upper_bound(b[i].begin(), b[i].end(), x + 2LL * (m - 1) + 1) - lower_bound(b[i].begin(), b[i].end(), x);
}
}
printf("%lld\n", ans);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
二分答案之后树形DP即可。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 100005;
const double eps = 1e-7;
double mid, l[N], r[N];
vector <int> adj[N];
bool e[N], f[N];
char opt[10];
int n, v[N];
inline bool DFS(int x, int p) {
if (e[x]) {
f[x] = true;
} else {
f[x] = false, l[x] = r[x] = v[x];
}
for (auto y : adj[x]) {
if (y != p) {
if (!DFS(y, x)) {
return false;
}
if (!f[y]) {
if (f[x]) {
f[x] = false, l[x] = l[y] - mid, r[x] = r[y] + mid;
} else {
CheckMax(l[x], l[y] - mid), CheckMin(r[x], r[y] + mid);
}
}
}
}
return f[x] || l[x] <= r[x] + eps;
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n);
for (int i = 1; i <= n; ++i) {
scanf("%s", opt);
if (opt[0] == '*') {
e[i] = true;
} else {
sscanf(opt, "%d", &v[i]);
}
}
for (int i = 1, x, y; i < n; ++i) {
Read(x), Read(y);
adj[x].pb(y), adj[y].pb(x);
}
double l = 0, r = 2e6;
while (r - l > eps) {
mid = (l + r) / 2;
if (DFS(1, 0)) {
r = mid;
} else {
l = mid;
}
}
printf("%lf\n", l);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
一个结论是,记 fi f i 表示权值是 2i 2 i 的匹配个数,一定存在一个最优解,满足 f19,f18,⋯ f 19 , f 18 , ⋯ 字典序最大。
证明可以用调整法,假设某个匹配在 fi f i 处小于最优解的 fi f i ,那么至少有一条边 (u,v) ( u , v ) 满足其权值为 2i 2 i 而没有被匹配,将它们匹配,至多减少 2 2 条权值为 2i−1 2 i − 1 的边,不会变劣。
剩下就是构建一个网络流图,建立 20 20 个二进制位点记为 biti b i t i ,如果 ai a i 第 j j 位为 1 1 那么 i i 向 bitj b i t j 连边,然后按位贪心即可,这个过程可以用Hall定理优化。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 1048580;
int n, m, a[N], b[N], ret[N];
LL ans;
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m);
for (int i = 0, x; i < n; ++i) {
Read(x), ++a[(1 << 20) - 1 ^ x];
}
for (int i = 0, x; i < m; ++i) {
Read(x), ++b[(1 << 20) - 1 ^ x];
}
for (int i = 1; i < 1 << 20; i <<= 1) {
for (int j = 0; j < 1 << 20; j += i << 1) {
for (int k = 0; k < i; ++k) {
a[j + k] += a[j + k + i], b[j + k] += b[j + k + i];
}
}
}
for (int i = 0; i < 1 << 20; ++i) {
a[i] = n - a[i], b[i] = m - b[i];
}
for (int i = 19; ~i; --i) {
int lim = 1 << 30;
for (int j = 1 << i; j < 1 << i + 1; ++j) {
CheckMin(lim, min(a[j], b[j]));
}
ans += (LL)lim << i;
for (int j = 1 << i; j < 1 << i + 1; ++j) {
CheckMin(a[j - (1 << i)], a[j] - lim);
CheckMin(b[j - (1 << i)], b[j] - lim);
}
}
printf("%lld\n", ans);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
首先将第一行补到最后一行,然后就不用管首尾行的影响了。
记 f(i,j) f ( i , j ) 表示考虑前 i i 行, i i 这一行移动 j j 格是否可行, g(i,j) g ( i , j ) 表示第 i−1 i − 1 行不动,第 i i 行移动 j j 格是否不与第 i−1 i − 1 行矛盾,转移可以用FFT,输出方案直接暴力就行了。
#include
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 2097155;
const double pi = acos(-1);
struct E {
double x, y;
E(double x = 0, double y = 0):x(x), y(y) {}
E operator + (const E &b) const {
return E(x + b.x, y + b.y);
}
E operator - (const E &b) const {
return E(x - b.x, y - b.y);
}
E operator * (const E &b) const {
return E(x * b.x - y * b.y, x * b.y + y * b.x);
}
} w[N], x[N], y[N], z[N];
int n, m, D, L, p[N], q[N], r[N], R[N], ans[N];
bool ff[N], gg[N], *f[N], *g[N];
char ss[N], *s[N];
inline void DFT(E *x, E *w) {
for (int i = 0; i < D; ++i) {
if (i < R[i]) {
swap(x[i], x[R[i]]);
}
}
for (int i = 1, l = L - 1; i < D; i <<= 1, --l) {
for (int j = 0; j < D; j += i << 1) {
for (int k = 0; k < i; ++k) {
E u = x[j + k], v = x[j + k + i] * w[k * (1 << l)];
x[j + k] = u + v, x[j + k + i] = u - v;
}
}
}
}
inline void Mul(int *a, int n, int *b, int m, int *c) {
for (D = 1, L = 0; D < n + m - 1; D <<= 1, ++L);
for (int i = 1; i < D; ++i) {
R[i] = (R[i >> 1] >> 1) | ((i & 1) << L - 1);
}
for (int i = 0; i < D; ++i) {
z[i] = w[i] = E(cos(2 * pi * i / D), sin(2 * pi * i / D)), w[i].y = -w[i].y;
x[i] = i < n ? E(a[i], 0) : E(0, 0), y[i] = i < m ? E(b[i], 0) : E(0, 0);
}
DFT(x, z), DFT(y, z);
for (int i = 0; i < D; ++i) {
x[i] = x[i] * y[i];
}
DFT(x, w);
for (int i = 0; i < n + m - 1; ++i) {
c[i] = x[i].x / D + 0.5;
}
}
inline int Get(int i, int j) {
return (s[i][j] == 'X') << 1 | (s[i][(j + 1) % m] == 'X');
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m);
for (int i = 0; i <= n; ++i) {
s[i] = ss + i * (m + 1);
f[i] = ff + i * (m + 1);
g[i] = gg + i * (m + 1);
}
for (int i = 0; i < n; ++i) {
scanf("%s", s[i]);
}
for (int i = 0; i < m; ++i) {
s[n][i] = s[0][i];
}
f[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int t = 1; t <= 3; ++t) {
for (int j = 0; j < m; ++j) {
p[j] = Get(i - 1, m - 1 - j) == t, q[j] = q[j + m] = Get(i, j) && Get(i, j) != t;
}
Mul(p, m, q, m << 1, r);
for (int j = 0; j < m; ++j) {
g[i][j] |= r[m - 1 + j];
}
}
for (int j = 0; j < m; ++j) {
g[i][j] = !g[i][j];
}
for (int j = 0; j < m; ++j) {
p[j] = f[i - 1][j], q[j] = q[j + m] = g[i][j];
}
Mul(p, m, q, m << 1, r);
for (int j = 0; j < m; ++j) {
f[i][j] = r[j + m];
}
}
for (int i = n, cur = 0; i; --i) {
for (int j = 0; j < m; ++j) {
if (f[i - 1][j] && g[i][(cur - j + m) % m]) {
ans[i - 1] = cur = j;
break;
}
}
}
for (int i = 0; i < n; ++i) {
for (int j = ans[i]; j < m; ++j) {
putchar(s[i][j]);
}
for (int j = 0; j < ans[i]; ++j) {
putchar(s[i][j]);
}
putchar(10);
}
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}