点击打开链接
点击打开链接
输出 s 1 s 2 s 3 s_1s_2s_3 s1s2s3 即可。
时间复杂度 O ( ∣ S ∣ ) O(|S|) O(∣S∣) 。
#include
using namespace std;
const int MAXN = 3e5 + 5;
typedef long long ll;
template void chkmax(T &x, T y) {x = max(x, y); }
template void chkmin(T &x, T y) {x = min(x, y); }
template void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
char s[MAXN];
int main() {
scanf("%s", s + 1), s[4] = 0;
printf("%s\n", s + 1);
return 0;
}
判断 T × ( V − W ) T\times (V-W) T×(V−W) 与 ∣ A − B ∣ |A-B| ∣A−B∣ 的大小关系即可。
时间复杂度 O ( 1 ) O(1) O(1) 。
#include
using namespace std;
const int MAXN = 3e5 + 5;
typedef long long ll;
template void chkmax(T &x, T y) {x = max(x, y); }
template void chkmin(T &x, T y) {x = min(x, y); }
template void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int main() {
int a, v, b, w, t;
read(a), read(v), read(b), read(w), read(t);
int dist = abs(a - b);
if (v > w && 1ll * t * (v - w) >= dist) puts("YES");
else puts("NO");
return 0;
}
考虑初始时 A i = 0 A_i=0 Ai=0 的情况,则经过 O ( L o g N ) O(LogN) O(LogN) 次操作后,应当有 A i = N A_i=N Ai=N 。
因此,有效操作的轮数不会超过 O ( L o g N ) O(LogN) O(LogN) 。模拟,直到 A i = N A_i=N Ai=N 或是操作次数用尽即可。
时间复杂度 O ( N L o g N ) O(NLogN) O(NLogN) 。
#include
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
template void chkmax(T &x, T y) {x = max(x, y); }
template void chkmin(T &x, T y) {x = min(x, y); }
template void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int n, k, a[MAXN];
bool work() {
static int s[MAXN];
memset(s, 0, sizeof(s));
for (int i = 1; i <= n; i++) {
int l = max(1, i - a[i]), r = min(n, i + a[i]);
s[l]++, s[r + 1]--;
}
bool res = false;
for (int i = 1; i <= n; i++) {
s[i] += s[i - 1];
if (s[i] != a[i]) {
res = true;
a[i] = s[i];
}
}
return res;
}
int main() {
read(n), read(k);
for (int i = 1; i <= n; i++)
read(a[i]);
for (int i = 1; i <= k; i++)
if (!work()) break;
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
一种可行的暴力是记 d p i , j dp_{i,j} dpi,j 表示考虑节点 i i i 及其祖先,剩余 j j j 容量的背包的最优解。
则 d p i dp_{i} dpi 显然可以通过 O ( L ) O(L) O(L) 的扫描由 d p ⌊ i 2 ⌋ dp_{\lfloor\frac{i}{2}\rfloor} dp⌊2i⌋ 转移得到。
该做法的预处理复杂度为 O ( N × L ) O(N\times L) O(N×L) ,单组询问的复杂度为 O ( 1 ) O(1) O(1) 。
另一种可行的暴力是直接枚举选取物品的集合。
由于树高不超过 O ( L o g N ) O(LogN) O(LogN) ,该做法的预处理复杂度为 O ( 1 ) O(1) O(1) ,单组询问的复杂度为 O ( N ) O(N) O(N) 。
取 α = O ( N ) \alpha=O(\sqrt{N}) α=O(N) ,按照第一种方法计算 d p i ( i ≤ α ) dp_{i}\;(i\leq \alpha) dpi(i≤α) ,则可以 O ( 1 ) O(1) O(1) 回答出现位置 ≤ α \leq \alpha ≤α 的询问。
对于剩余询问,枚举 ≥ α \geq \alpha ≥α 的物品是否选取,并用 d p dp dp 值计算 ≤ α \leq \alpha ≤α 的物品的最优选取方案即可。
时间复杂度 O ( ( L + Q ) N ) O((L+Q)\sqrt{N}) O((L+Q)N) 。
#include
using namespace std;
const int MAXN = 3e5 + 5;
const int MAXV = 1e5 + 5;
const int MAXM = 1 << 9;
typedef long long ll;
template void chkmax(T &x, T y) {x = max(x, y); }
template void chkmin(T &x, T y) {x = min(x, y); }
template void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int a[MAXM][MAXV];
int n, m, r, q, v[MAXN], w[MAXN];
int query(int x, int y) {
if (x <= m) return a[x][y];
else {
int ans = query(x / 2, y);
if (y >= w[x]) chkmax(ans, v[x] + query(x / 2, y - w[x]));
return ans;
}
}
int main() {
read(n), m = (1 << 9) - 1, r = 1e5;
for (int i = 1; i <= n; i++)
read(v[i]), read(w[i]);
for (int i = 1; i <= m; i++) {
int f = i / 2;
for (int j = 1; j <= r; j++) {
a[i][j] = a[f][j];
if (j >= w[i]) chkmax(a[i][j], v[i] + a[f][j - w[i]]);
}
}
read(q);
for (int i = 1; i <= q; i++) {
int x, y; read(x), read(y);
printf("%d\n", query(x, y));
}
return 0;
}
不妨认为 S = 0 , T = 2 k − 1 S=0,T=2^k-1 S=0,T=2k−1 ,且 S ≤ A i ≤ T S\leq A_i\leq T S≤Ai≤T 。
则题目中的要求等价于:对于每一个二进制位,选出的集合既有 0 0 0 ,也有 1 1 1 。
考虑枚举选择的集合中第一个元素,则对于每个二进制位,已经存在了 0 , 1 0,1 0,1 中的一者。
剩余问题可转换为:选择一个集合,使得集合的二进制与的结果为 0 0 0 ,求方案数。
则用 FWT 配合容斥原理解决转化后的问题即可。
时间复杂度 O ( N × V L o g V + N 2 ) O(N\times VLogV+N^2) O(N×VLogV+N2) 。
官方题解中,给出了一种复杂度更为优秀的解法。
#include
using namespace std;
const int MAXN = 55;
const int MAXV = 1 << 18;
typedef long long ll;
template void chkmax(T &x, T y) {x = max(x, y); }
template void chkmin(T &x, T y) {x = min(x, y); }
template void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
ll coef[MAXN], binom[MAXN][MAXN];
int cnt[MAXV], bits[MAXV];
int m, goal, n, k, s, t, bit[MAXN], a[MAXN];
bool inc(int x, int y) {
return (x | y) == x;
}
void FWTOR(int *a, int N) {
for (int len = 2; len <= N; len <<= 1)
for (int s = 0; s < N; s += len)
for (int i = s, j = s + len / 2; j < s + len; i++, j++)
a[i] = a[i] + a[j];
}
int main() {
read(m), read(k), read(s), read(t);
if (!inc(t, s)) {
puts("0");
return 0;
}
for (int i = 1; i <= m; i++) {
int x; read(x);
if (inc(x, s) && inc(t, x)) a[++n] = x;
}
m = 0, goal = 0;
for (int i = 1; i <= 18; i++) {
bit[i] = 1 << (i - 1);
if ((t & bit[i]) && (s & bit[i]) == 0) m++, goal = goal * 2 + 1;
}
for (int i = 1; i <= n; i++) {
int res = 0;
for (int j = 1; j <= 18; j++)
if ((t & bit[j]) && (s & bit[j]) == 0) {
if (a[i] & bit[j]) res = res * 2 + 1;
else res = res * 2;
}
a[i] = res;
}
for (int i = 0; i <= n; i++) {
binom[i][0] = 1;
for (int j = 1; j <= i; j++)
binom[i][j] = binom[i - 1][j - 1] + binom[i - 1][j];
for (int j = 0; j <= k - 1; j++)
coef[i] += binom[i][j];
}
for (int i = 1; i <= goal; i++)
bits[i] = bits[i / 2] + i % 2;
ll ans = 0;
for (int i = 1; i <= n; i++) {
memset(cnt, 0, sizeof(cnt));
for (int j = i + 1; j <= n; j++)
cnt[a[i] ^ a[j] ^ goal]++;
FWTOR(cnt, goal + 1);
for (int j = 0; j <= goal; j++)
if (bits[j] & 1) ans -= coef[cnt[j]];
else ans += coef[cnt[j]];
}
cout << ans << endl;
return 0;
}
不失一般性地,考虑顶点在 ( 0 , i ) , ( j , 0 ) , ( W , k ) (0,i),(j,0),(W,k) (0,i),(j,0),(W,k) 处的三角形。
由对称性,考虑仅计算 i ≤ k i\leq k i≤k 的情况,令 k = i + d k=i+d k=i+d 。
由毕克定理,三角形内部的点数 A A A ,边界上的点数 B B B ,面积 S S S 应当满足
2 S = 2 A + B − 2 2S=2A+B-2 2S=2A+B−2
也即
( 2 i + d ) W − i j − ( W − j ) ( i + d ) = 2 A + g c d ( i , j ) + g c d ( W , d ) + g c d ( W − j , i + d ) − 2 (2i+d)W-ij-(W-j)(i+d)=2A+gcd(i,j)+gcd(W,d)+gcd(W-j,i+d)-2 (2i+d)W−ij−(W−j)(i+d)=2A+gcd(i,j)+gcd(W,d)+gcd(W−j,i+d)−2
整理得
i W − g c d ( i , j ) − g c d ( W − j , i + d ) = 2 A + g c d ( W , d ) − 2 − d j iW-gcd(i,j)-gcd(W-j,i+d)=2A+gcd(W,d)-2-dj iW−gcd(i,j)−gcd(W−j,i+d)=2A+gcd(W,d)−2−dj
因此,我们需要计算满足如下不等式的 ( i , j , d ) (i,j,d) (i,j,d) 的个数:
i W − g c d ( i , j ) − g c d ( W − j , i + d ) ≤ 2 K + g c d ( W , d ) − 2 − d j iW-gcd(i,j)-gcd(W-j,i+d)\leq 2K+gcd(W,d)-2-dj iW−gcd(i,j)−gcd(W−j,i+d)≤2K+gcd(W,d)−2−dj
考虑枚举 ( j , d ) (j,d) (j,d) 则不等式的右侧应当为一个定值。
由于 g c d ( i , j ) + g c d ( W − j , i + d ) ≤ j + ( W − j ) = W gcd(i,j)+gcd(W-j,i+d)\leq j+(W-j)=W gcd(i,j)+gcd(W−j,i+d)≤j+(W−j)=W ,即不等式左侧关于 i i i 单调。
因此,我们可以 O ( 1 ) O(1) O(1) 算出满足不等式的 i i i 的个数。
又因为使得不等式右侧 ≥ 0 \geq 0 ≥0 的 ( j , d ) (j,d) (j,d) 的组数不超过 O ( V L o g V ) O(VLogV) O(VLogV) ,枚举即可。
时间复杂度 O ( V L o g 2 V ) O(VLog^2V) O(VLog2V) 。
#include
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
template void chkmax(T &x, T y) {x = max(x, y); }
template void chkmin(T &x, T y) {x = min(x, y); }
template void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int n, m, k;
ll work(int n, int m) {
ll ans = 0;
for (int i = 0; i <= n - 2; i++)
for (int j = 1; j <= m - 1 && i * j <= 2 * k + m; j++) {
int tmp = 2 * k + __gcd(i, m) - i * j - 2;
if (tmp >= 0) {
int limit = min(n - 1 - i, tmp / m + 1);
ans += (limit - (m * limit - __gcd(limit, j) - __gcd(limit + i, m - j) > tmp)) * (1 + (i != 0));
}
}
return ans;
}
int main() {
read(n), read(m), read(k);
cout << work(n, m) * 2 + work(m, n) * 2 << endl;
return 0;
}