边做边更吧。。。
最佳团体
分数规划+ t r e e d p treedp treedp 即可。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define eps 1e-6
using namespace std;
typedef long long LL;
double _max(double x, double y) {return x > y ? x : y;}
double _min(double x, double y) {return x < y ? x : y;}
const int N = 2501;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
struct edge {
int x, y, next;
} e[2 * N]; int len, last[N];
int cnt, K, n, s[N], p[N], tot[N];
double c[N], f[N][N], l[N];
void ins(int x, int y) {
e[++len].x = x, e[len].y = y;
e[len].next = last[x], last[x] = len;
}
void treedp(int x) {
f[x][0] = 0, f[x][1] = c[x]; tot[x] = 1;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
treedp(y);
for(int i = 1; i <= tot[x] + tot[y]; i++) l[i] = -999999999;
for(int i = 1; i <= tot[x]; i++) {
for(int j = 0; j <= tot[y]; j++) {
l[i + j] = _max(l[i + j], f[x][i] + f[y][j]);
}
} tot[x] += tot[y];
for(int i = 1; i <= tot[x]; i++) f[x][i] = l[i];
}
}
bool check(double mid) {
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; i++) c[i] = (double)s[i] - mid * p[i];
treedp(0);
return f[0][K + 1] >= 0;
}
int main() {
K = read(), n = read();
for(int i = 1; i <= n; i++) {
p[i] = read(), s[i] = read();
int x = read(); ins(x, i);
} double l = 0, r = 1e4, ans;
while(r - l >= eps) {
double mid = (l + r) / 2.0;
if(check(mid)) l = mid + eps, ans = mid;
else r = mid - eps;
} printf("%.3lf\n", ans);
return 0;
}
独特的树叶
判断两棵树是否相同可以使用树
H
a
s
h
Hash
Hash,
我用的
H
a
s
h
Hash
Hash方式是按照子树大小来
H
a
s
h
Hash
Hash。
然后你搞一个换根
D
P
DP
DP判一下即可。
#include <map>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const int N = 100002;
const LL P1 = 71, P2 = 131;
const LL mod = 1e9 + 7;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
struct edge {
int x, y, next;
} e[2 * N]; int len, last[N];
map<LL, bool> mp1, mp2;
int n, tot[N], ru[N];
LL Hash1[N], Hash2[N];
int ms;
void ins(int x, int y) {
e[++len].x = x, e[len].y = y;
e[len].next = last[x], last[x] = len;
}
LL pow_mod(LL a, int k) {
LL ans = 1;
while(k) {
if(k & 1) (ans *= a) %= mod;
(a *= a) %= mod; k /= 2;
} return ans;
}
void dfs1(int x, int fa) {
tot[x] = 1; Hash1[x] = Hash2[x] = 0;
LL cnt1 = 1, cnt2 = 1;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa) {
dfs1(y, x);
tot[x] += tot[y];
(cnt1 *= Hash1[y]) %= mod;
(cnt2 *= Hash2[y]) %= mod;
}
} cnt1 = (LL)(cnt1 + tot[x]) * P1 % mod, cnt2 = (LL)(cnt2 + tot[x]) * P2 % mod;
Hash1[x] = cnt1, Hash2[x] = cnt2;
}
void dfs2(int x, int fa) {
mp1[Hash1[x]] = mp2[Hash2[x]] = 1;
LL zz1 = (Hash1[x] - P1 * n % mod + mod) % mod;
LL zz2 = (Hash2[x] - P2 * n % mod + mod) % mod;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa) {
LL g1 = (zz1 * pow_mod(Hash1[y], mod - 2) % mod + P1 * (n - tot[y]) % mod) % mod;
LL g2 = (zz2 * pow_mod(Hash2[y], mod - 2) % mod + P2 * (n - tot[y]) % mod) % mod;
Hash1[y] = ((Hash1[y] - P1 * tot[y] % mod + mod) % mod * g1 % mod + P1 * n % mod) % mod;
Hash2[y] = ((Hash2[y] - P2 * tot[y] % mod + mod) % mod * g2 % mod + P2 * n % mod) % mod;
dfs2(y, x);
}
}
}
void dfs3(int x, int fa) {
LL zz1 = (Hash1[x] - P1 * (n + 1) % mod + mod) % mod;
LL zz2 = (Hash2[x] - P2 * (n + 1) % mod + mod) % mod;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa) {
LL g1 = (zz1 * pow_mod(Hash1[y], mod - 2) % mod + P1 * (n + 1 - tot[y]) % mod) % mod;
LL g2 = (zz2 * pow_mod(Hash2[y], mod - 2) % mod + P2 * (n + 1 - tot[y]) % mod) % mod;
if(x == 1 && ru[x] == 1) {
if(mp1[Hash1[y]] && mp2[Hash2[y]]) ms = _min(ms, x);
} if(ru[y] == 1 && mp1[g1] && mp2[g2]) ms = _min(ms, y);
Hash1[y] = ((Hash1[y] - P1 * tot[y] % mod + mod) % mod * g1 % mod + P1 * (n + 1) % mod) % mod;
Hash2[y] = ((Hash2[y] - P2 * tot[y] % mod + mod) % mod * g2 % mod + P2 * (n + 1) % mod) % mod;
dfs3(y, x);
}
}
}
int main() {
n = read();
for(int i = 1; i < n; i++) {
int x = read(), y = read();
ins(x, y), ins(y, x);
} dfs1(1, 0),
dfs2(1, 0);
len = 0; memset(last, 0, sizeof(last));
for(int i = 1; i <= n; i++) {
int x = read(), y = read();
ins(x, y), ins(y, x), ru[x]++, ru[y]++;
} dfs1(1, 0), ms = 999999999,
dfs3(1, 0);
printf("%d\n", ms);
return 0;
}
扭动的回文串
容易发现一个结论,以 A A A串为例,答案肯定就是就是以某个点为中心在 A A A串中的最长回文串,在 B B B串中往右拓一段, A A A串中往左拓一段,然后直接二分 H a s h Hash Hash。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const int N = 100003;
const ULL P = 233;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
int m1[N], m2[N];
ULL s1[2][N], s2[2][N], o[N];
char ss1[N], ss2[N];
int main() {
int n = read();
scanf("%s", ss1 + 1);
scanf("%s", ss2 + 1);
s1[0][0] = 0, s2[0][0] = 0;
for(int i = 1; i <= n; i++) s1[0][i] = s1[0][i - 1] * P + ss1[i], s2[0][i] = s2[0][i - 1] * P + ss2[i];
s1[1][n + 1] = s2[1][n + 1] = 0;
for(int i = n; i >= 1; i--) s1[1][i] = s1[1][i + 1] * P + ss1[i], s2[1][i] = s2[1][i + 1] * P + ss2[i];
o[0] = 1; for(int i = 1; i <= n; i++) o[i] = o[i - 1] * P;
int ans = 0;
for(int i = 1; i <= n; i++) {
int l = 1, r = _min(i, n - i + 1), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s1[1][i] - s1[1][i + mid] * o[mid] == s1[0][i] - s1[0][i - mid] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} m1[i] = hh;
ans = _max(ans, hh * 2 - 1);
} for(int i = 1; i <= n; i++) {
int l = 1, r = _min(i, n - i + 1), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s2[1][i] - s2[1][i + mid] * o[mid] == s2[0][i] - s2[0][i - mid] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} m2[i] = hh;
ans = _max(ans, hh * 2 - 1);
} for(int i = 1; i <= n; i++) {
int l = 1, r = _min(i - m1[i], n - (i + m1[i] - 1) + 1), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s1[0][i - m1[i]] - s1[0][i - m1[i] - mid] * o[mid] == s2[1][i + m1[i] - 1] - s2[1][i + m1[i] + mid - 1] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} ans = _max(ans, (m1[i] + hh) * 2 - 1);
} for(int i = 1; i <= n; i++) {
int l = 1, r = _min(i - m2[i] + 1, n - (i + m2[i] - 1)), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s2[1][i + m2[i]] - s2[1][i + m2[i] + mid] * o[mid] == s1[0][i - m2[i] + 1] - s1[0][i - m2[i] - mid + 1] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} ans = _max(ans, (m2[i] + hh) * 2 - 1);
} for(int i = 1; i < n; i++) {
int l = 1, r = _min(i, n - i), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s1[0][i] - s1[0][i - mid] * o[mid] == s1[1][i + 1] - s1[1][i + mid + 1] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} m1[i] = hh;
ans = _max(ans, hh * 2);
} for(int i = 1; i < n; i++) {
int l = 1, r = _min(i, n - i), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s2[0][i] - s2[0][i - mid] * o[mid] == s2[1][i + 1] - s2[1][i + mid + 1] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} m2[i] = hh;
ans = _max(ans, hh * 2);
} for(int i = 1; i < n; i++) {
int l = 1, r = _min(i - m1[i], n - (i + m1[i]) + 1), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s1[0][i - m1[i]] - s1[0][i - m1[i] - mid] * o[mid] == s2[1][i + m1[i]] - s2[1][i + m1[i] + mid] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} ans = _max(ans, (hh + m1[i]) * 2);
} for(int i = 1; i < n; i++) {
int l = 1, r = _min(i - m2[i] + 1, n - (i + m2[i])), hh = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s2[1][i + m2[i] + 1] - s2[1][i + m2[i] + mid + 1] * o[mid] == s1[0][i - m2[i] + 1] - s1[0][i - m2[i] - mid + 1] * o[mid]) l = mid + 1, hh = mid;
else r = mid - 1;
} ans = _max(ans, (hh + m2[i]) * 2);
} printf("%d\n", ans);
return 0;
}
灯塔
后面那部分不同的值不超过根号,然后我就写了个根号就过了。
看了一下
L
O
J
LOJ
LOJ的评论,这好像不是正解,想了一下这种东西应该是满足决策单调性的吧,不写了。。。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
int f[20][100001], Log[100001], bin[20];
int getmx(int l, int r) {
int hh = Log[r - l + 1];
return _max(f[hh][l], f[hh][r - bin[hh] + 1]);
}
int main() {
int n = read();
bin[0] = 1; for(int i = 1; i <= 18; i++) bin[i] = bin[i - 1] << 1;
Log[1] = 0; for(int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;
for(int i = 1; i <= n; i++) f[0][i] = read();
for(int i = 1; i <= 18; i++) for(int j = 1; j <= n - bin[i] + 1; j++) f[i][j] = _max(f[i - 1][j], f[i - 1][j + bin[i - 1]]);
for(int i = 1; i <= n; i++) {
int ans = 0, z = 1;
while(1) {
int r = i - (z - 1) * (z - 1) - 1;
if(r < 1) break;
int l = _max(1, i - z * z);
ans = _max(ans, getmx(l, r) + z);
z++;
} z = 1;
while(1) {
int l = i + (z - 1) * (z - 1) + 1;
if(l > n) break;
int r = _min(n, i + z * z);
ans = _max(ans, getmx(l, r) + z);
z++;
} ans -= f[0][i];
put(_max(ans, 0)), puts("");
} return 0;
}
位运算
设
f
[
S
]
f[S]
f[S]为
S
S
S表示
n
n
n个位置是否顶着上界,这样子转移的话,会不满足
n
n
n个数互不相同的限制。
考虑更改一下状态,让序列变得有序,设
f
[
S
]
f[S]
f[S]为每一位是否跟后一位相同,最后一位表示是否顶格,这样矩乘一下即可。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const LL mod = 1e9 + 7;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
int n, k;
char ss[51];
int bin[10], one[1 << 7];
struct matrix {
int f[128][128];
matrix() {memset(f, 0, sizeof(f));}
friend matrix operator * (matrix a, matrix b) {
matrix c;
for(int i = 0; i < bin[n]; i++) {
for(int j = 0; j < bin[n]; j++) {
for(int k = 0; k < bin[n]; k++) {
(c.f[i][j] += (LL)a.f[i][k] * b.f[k][j] % mod) %= mod;
}
}
} return c;
}
} ans, sum, now;
int main() {
n = read(), k = read();
scanf("%s", ss + 1);
int S = strlen(ss + 1);
bin[0] = 1; for(int i = 1; i <= 7; i++) bin[i] = bin[i - 1] << 1;
for(int i = 0; i < bin[n]; i++) {
sum.f[i][i] = 1;
if(i) one[i] = one[i >> 1] + (i & 1);
} ans.f[0][bin[n] - 1] = 1;
for(int i = 1; i <= S; i++) {
memset(now.f, 0, sizeof(now.f));
for(int j = 0; j < bin[n]; j++) {
for(int k = 0; k < bin[n]; k++) if(!(one[k] & 1)){
int s = 0; bool bk = 0;
if(ss[i] == '0') {
if(j & bin[n - 1]) {
if(k & bin[n - 1]) break;
s += bin[n - 1];
if(bk) continue;
for(int u = 1; u < n; u++) {
if((j & bin[u - 1])) {
if((k & bin[u - 1]) && !(k & bin[u])) {bk = 1; break;}
if((k & bin[u - 1]) && (k & bin[u])) s += bin[u - 1];
else if(!(k & bin[u - 1]) && !(k & bin[u])) s += bin[u - 1];
}
} if(bk) continue;
} else {
for(int u = 1; u < n; u++) {
if((j & bin[u - 1])) {
if((k & bin[u - 1]) && !(k & bin[u])) {bk = 1; break;}
if((k & bin[u - 1]) && (k & bin[u])) s += bin[u - 1];
else if(!(k & bin[u - 1]) && !(k & bin[u])) s += bin[u - 1];
}
} if(bk) continue;
}
} else {
if(j & bin[n - 1]) {
if(k & bin[n - 1]) s += bin[n - 1];
for(int u = 1; u < n; u++) {
if((j & bin[u - 1])) {
if((k & bin[u - 1]) && !(k & bin[u])) {bk = 1; break;}
if((k & bin[u - 1]) && (k & bin[u])) s += bin[u - 1];
else if(!(k & bin[u - 1]) && !(k & bin[u])) s += bin[u - 1];
}
} if(bk) continue;
} else {
for(int u = 1; u < n; u++) {
if((j & bin[u - 1])) {
if((k & bin[u - 1]) && !(k & bin[u])) {bk = 1; break;}
if((k & bin[u - 1]) && (k & bin[u])) s += bin[u - 1];
else if(!(k & bin[u - 1]) && !(k & bin[u])) s += bin[u - 1];
}
} if(bk) continue;
}
} now.f[j][s]++;
}
} sum = sum * now;
} while(k) {
if(k & 1) ans = ans * sum;
sum = sum * sum; k /= 2;
} put(ans.f[0][0]);
return 0;
}
飞机调度
f l o y d floyd floyd一下,就是最小链覆盖的模型。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
struct edge {
int x, y, next;
} e[501 * 501]; int len, last[501];
struct node {int x, y, d;} b[501];
int tt, match[501], chw[501];
int a[501], f[501][501], bak[501][501];
void ins(int x, int y) {
e[++len].x = x, e[len].y = y;
e[len].next = last[x], last[x] = len;
}
bool findmuniu(int x) {
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(chw[y] != tt) {
chw[y] = tt;
if(!match[y] || findmuniu(match[y])) {
match[y] = x; return 1;
}
}
} return 0;
}
int main() {
int n = read(), m = read();
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
bak[i][j] = f[i][j] = read();
if(i != j) f[i][j] += a[j];
}
} for(int k = 1; k <= n; k++) {
for(int i = 1; i <= n; i++) if(i != k){
for(int j = 1; j <= n; j++) if(i != j && j != k){
f[i][j] = _min(f[i][j], f[i][k] + f[k][j]);
}
}
} for(int i = 1; i <= m; i++) b[i].x = read(), b[i].y = read(), b[i].d = read();
for(int i = 1; i <= m; i++) for(int j = 1; j <= m; j++) if(i != j){
if(b[i].d + bak[b[i].x][b[i].y] + a[b[i].y] + f[b[i].y][b[j].x] <= b[j].d) ins(i, j);
} int ans = 0;
for(int i = 1; i <= m; i++) {
tt++; if(findmuniu(i)) ans++;
} printf("%d\n", m - ans);
return 0;
}
无界单词
第一问的话考虑设
f
[
i
]
f[i]
f[i]表示长度为
i
i
i的无界单词合法个数,
考虑容斥,则:
f
[
i
]
=
2
i
−
∑
j
=
1
i
/
2
f
[
j
]
∗
2
i
−
2
j
f[i]=2^{i}-\sum_{j=1}^{i/2}f[j]*2^{i-2j}
f[i]=2i−j=1∑i/2f[j]∗2i−2j
为什么只用枚举到
i
/
2
i/2
i/2?如果大于
i
/
2
{i/2}
i/2就不会有合法无界单词的了。。。
第二问用类似的方法去
D
P
DP
DP,考虑按位确定,若当前有
l
e
n
len
len位已经确定了。
转移
i
i
i的时候,对
j
j
j分类讨论一下:
若
i
<
=
l
e
n
i<=len
i<=len,因为前
l
e
n
len
len位已经确定,所以直接判是否合法即可。
若
j
>
=
l
e
n
j>=len
j>=len,则
f
[
j
]
f[j]
f[j]也已经确定,且不受前
l
e
n
len
len位影响,直接转移即可。
若
j
+
l
e
n
<
=
i
j+len<=i
j+len<=i,说明后
j
j
j位与前
l
e
n
len
len位无交,直接转移。
否则,说明与前
l
e
n
len
len位有交,直接判断合法即可。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
ULL read() {
ULL s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(ULL x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
ULL K, bin[65], f[65];
int n, cnt, p[65], a[65];
void getnxt(int i) {
if(i == 1) {p[1] = 0; return ;}
int j = p[i - 1];
while(j && a[j + 1] != a[i]) j = p[j];
p[i] = j + (a[j + 1] == a[i]);
}
ULL chk(int i) {return p[i] == 0;}
ULL chk2(int x) {
for(int i = 1; i <= x; i++) if(a[i] != a[cnt - x + i]) return 0;
return 1;
}
ULL solve() {
for(int i = 1; i <= n; i++) {
if(i <= cnt) f[i] = chk(i);
else {
f[i] = bin[i - cnt];
for(int j = 1; j * 2 <= i; j++) {
if(j >= cnt) f[i] -= f[j] * bin[i - j * 2];
else if(j + cnt <= i) f[i] -= f[j] * bin[i - j - cnt];
else f[i] -= f[j] * chk2(j + cnt - i);
}
}
} return f[n];
}
int main() {
int tt = read();
bin[0] = 1LL; for(int i = 1; i <= 64; i++) bin[i] = bin[i - 1] << 1;
while(tt--) {
n = read(), K = read();
cnt = 0; LL ans = solve();
put(ans), puts("");
for(int i = 1; i <= n; i++) {
a[i] = 0, getnxt(i); cnt++;
ULL u = solve();
if(K > u) K -= u, a[i] = 1, getnxt(i);
} for(int i = 1; i <= n; i++) putchar(a[i] + 'a');
puts("");
} return 0;
}
轻重路径
这题你可以尝试反着做,然后就相当于把一条路径上的一部分轻链变成重链。
树剖一下,你要开一颗线段树维护每一个点与父亲的连边是否是轻链,开一颗线段树维护子树内当前最晚被删掉的点,还要维护当前每个点的子树大小,好烦啊。。。
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const int N = 200001;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(LL x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
int n;
struct Bit {
int s[N];
int lowbit(int x) {return x & -x;}
void change(int x, int c) {for(int i = x;i <= n; i += lowbit(i)) s[i] += c;}
int getsum(int x) {int sum = 0; for(int i = x; i; i -= lowbit(i)) sum += s[i]; return sum;}
} s;
int tp, sta[N]; LL ans;
struct seg1 {
int cnt, lc[N * 2], rc[N * 2], c[N * 2];
void bt(int l, int r) {
int now = ++cnt;
lc[now] = rc[now] = -1;
if(l < r) {
int mid = (l + r) / 2;
lc[now] = cnt + 1; bt(l, mid);
rc[now] = cnt + 1; bt(mid + 1, r);
}
}
void change(int now, int l, int r, int p, int C) {
if(l == r) {c[now] = C; return ;}
int mid = (l + r) / 2;
if(p <= mid) change(lc[now], l, mid, p, C);
else change(rc[now], mid + 1, r, p, C);
c[now] = c[lc[now]] + c[rc[now]];
}
void get(int now, int l, int r, int ll, int rr) {
if(l == r) {sta[++tp] = l; return ;}
int mid = (l + r) / 2;
if(l == ll && r == rr) {
if(c[lc[now]]) get(lc[now], l, mid, ll, mid);
if(c[rc[now]]) get(rc[now], mid + 1, r, mid + 1, rr);
return ;
} if(rr <= mid) {
if(c[lc[now]]) get(lc[now], l, mid, ll, rr);
}
else if(ll > mid) {
if(c[rc[now]]) get(rc[now], mid + 1, r, ll, rr);
}
else {
if(c[lc[now]]) get(lc[now], l, mid, ll, mid);
if(c[rc[now]]) get(rc[now], mid + 1, r, mid + 1, rr);
}
}
} t;
struct seg2 {
int cnt, lc[N * 2], rc[N * 2], c[N * 2];
void bt(int l, int r) {
int now = ++cnt;
lc[now] = rc[now] = -1;
c[now] = 0;
if(l < r) {
int mid = (l + r) / 2;
lc[now] = cnt + 1; bt(l, mid);
rc[now] = cnt + 1; bt(mid + 1, r);
}
}
void change(int now, int l, int r, int p, int C) {
if(l == r) {c[now] = C; return ;}
int mid = (l + r) / 2;
if(p <= mid) change(lc[now], l, mid, p, C);
else change(rc[now], mid + 1, r, p, C);
c[now] = _max(c[lc[now]], c[rc[now]]);
}
int get(int now, int l, int r, int ll, int rr) {
if(l == ll && r == rr) return c[now];
int mid = (l + r) / 2;if(rr <= mid) return get(lc[now], l, mid, ll, rr);
else if(ll > mid) return get(rc[now], mid + 1, r, ll, rr);
else return _max(get(lc[now], l, mid, ll, mid), get(rc[now], mid + 1, r, mid + 1, rr));
}
} t2;
struct edge {
int x, y, next;
} e[N]; int len, last[N];
int q[N];
int L[N], R[N], ll[N], rr[N], g[N];
int id, fa[N], tot[N], dep[N], son[N], top[N], ys[N], bak[N];
int zz = 0; LL pp[N];
int Son[N];
void ins(int x, int y) {
e[++len].x = x, e[len].y = y;
e[len].next = last[x], last[x] = len;
}
void pre_tree_node(int x) {
tot[x] = 1; ll[x] = ++id;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
dep[y] = dep[x] + 1;
fa[y] = x;
pre_tree_node(y);
tot[x] += tot[y];
if(tot[y] > tot[son[x]]) son[x] = y;
} rr[x] = id;
}
void pre_tree_edge(int x, int tp) {
ys[x] = ++id, top[x] = tp, bak[id] = x;
if(son[x]) pre_tree_edge(son[x], tp);
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != son[x]) pre_tree_edge(y, y);
}
}
void pre_tree_node_again(int x) {
s.change(ll[x], 1);
tot[x] = 1;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(!g[y]) {
pre_tree_node_again(y);
tot[x] += tot[y];
if(tot[y] > tot[Son[x]]) Son[x] = y;
}
} if(Son[x]) ans += Son[x];
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(!g[y]) {
if(Son[x] == y) t.change(1, 1, n, ys[y], 0);
else t.change(1, 1, n, ys[y], 1);
}
}
}
void solve(int x) {
int u = s.getsum(rr[fa[x]]) - s.getsum(ll[fa[x]] - 1);
if(u == 2) ans += x, t.change(1, 1, n, ys[x], 0);
tp = 0;
while(x) {
int tx = top[x];
t.get(1, 1, n, ys[tx], ys[x]);
x = fa[tx];
} for(int i = 1; i <= tp; i++) {
x = bak[sta[i]];
if(x == 1) break;
int f = fa[x];
if(L[f] == x) {
if(R[f]) {
int c1 = s.getsum(rr[x]) - s.getsum(ll[x] - 1);
int c2 = s.getsum(rr[R[f]]) - s.getsum(ll[R[f]] - 1);
if(c1 > c2) t.change(1, 1, n, ys[x], 0), t.change(1, 1, n, ys[R[f]], 1), ans -= R[f], ans += x;
else if(c1 == c2) {
int h1 = t2.get(1, 1, n, ll[x], rr[x]), h2 = t2.get(1, 1, n, ll[R[f]], rr[R[f]]);
if(h1 >= h2) t.change(1, 1, n, ys[x], 0), t.change(1, 1, n, ys[R[f]], 1), ans -= R[f], ans += x;
}
}
} else {
if(L[f]) {
int c1 = s.getsum(rr[x]) - s.getsum(ll[x] - 1);
int c2 = s.getsum(rr[L[f]]) - s.getsum(ll[L[f]] - 1);
if(c1 > c2) t.change(1, 1, n, ys[x], 0), t.change(1, 1, n, ys[L[f]], 1), ans -= L[f], ans += x;
else if(c1 == c2) {
int h1 = t2.get(1, 1, n, ll[x], rr[x]), h2 = t2.get(1, 1, n, ll[L[f]], rr[L[f]]);
if(h1 > h2) t.change(1, 1, n, ys[x], 0), t.change(1, 1, n, ys[L[f]], 1), ans -= L[f], ans += x;
}
}
}
}
}
int main() {
n = read();
for(int i = 1; i <= n; i++) {
L[i] = read(), R[i] = read();
if(R[i]) ins(i, R[i]);
if(L[i]) ins(i, L[i]);
g[i] = 0;
} int m = read();
for(int i = 1; i <= m; i++) q[i] = read(), g[q[i]] = i;
pre_tree_node(1), id = 0, pre_tree_edge(1, 1);
t.bt(1, n), t2.bt(1, n);
memset(tot, 0, sizeof(tot));
pre_tree_node_again(1);
for(int i = 1; i <= n; i++) {
if(g[i]) t.change(1, 1, n, ys[i], 1);
t2.change(1, 1, n, ll[i], g[i]);
}
pp[++zz] = ans;
for(int i = m; i >= 1; i--) {
int x = q[i];
t2.change(1, 1, n, ll[x], 0);
s.change(ll[x], 1);
solve(x);
pp[++zz] = ans;
} for(int i = zz; i >= 1; i--) put(pp[i]), puts("");
return 0;
}
反质数序列
你不管
1
1
1的情况,留着特判。
因为一个质数肯定是由奇数和偶数组成的,所以这是个二分图的最大独立集。
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const int C = 200001, N = 5002;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
struct edge {
int x, y, c, next;
} e[N * N]; int len, last[N];
int st, ed, h[N];
int plen, p[C];
queue<int> q;
bool v[C];
int a[N];
void ins(int x, int y, int c) {
e[++len].x = x, e[len].y = y, e[len].c = c;
e[len].next = last[x], last[x] = len;
e[++len].x = y, e[len].y = x, e[len].c = 0;
e[len].next = last[y], last[y] = len;
}
void get_p() {
for(int i = 2; i < C; i++) {
if(!v[i]) p[++plen] = i;
for(int j = 1; j <= plen && (LL)i * p[j] < C; j++) {
v[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
}
bool bfs() {
memset(h, 0, sizeof(h)); h[st] = 1;
q.push(st);
while(!q.empty()) {
int x = q.front(); q.pop();
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(!h[y] && e[k].c) {
h[y] = h[x] + 1;
q.push(y);
}
}
} if(!h[ed]) return 0;
return 1;
}
int dfs(int x, int flow) {
if(x == ed) return flow;
int tt = 0, minf;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(h[y] == h[x] + 1 && e[k].c && tt < flow) {
minf = dfs(y, _min(e[k].c, flow - tt));
e[k].c -= minf, e[k ^ 1].c += minf;
tt += minf;
}
} if(!tt) h[x] = 0;
return tt;
}
int main() {
get_p();
int n = read(); bool one = 0;
for(int i = 1; i <= n; i++) a[i] = read(), one |= a[i] == 1;
len = 1; st = 0, ed = n + 1; int yy = 0;
for(int i = 1; i <= n; i++) if(a[i] != 1){
yy++;
if(a[i] % 2 == 0) ins(st, i, 1);
else ins(i, ed, 1);
for(int j = i + 1; j <= n; j++) if(a[j] != 1){
if(!v[a[i] + a[j]]) {
if(a[i] % 2 == 0) ins(i, j, 1);
else ins(j, i, 1);
}
}
} int ans = 0;
while(bfs())
ans += dfs(st, 999999999);
ans = yy - ans;
if(one) {
len = 1; memset(last, 0, sizeof(last));
yy = 0;
for(int i = 1; i <= n; i++) if(a[i] != 1 && v[a[i] + 1]){
yy++;
if(a[i] % 2 == 0) ins(st, i, 1);
else ins(i, ed, 1);
for(int j = 1; j <= i + 1; j++) if(a[j] != 1 && v[a[j] + 1]){
if(!v[a[i] + a[j]]) {
if(a[i] % 2 == 0) ins(i, j, 1);
else ins(j, i, 1);
}
}
} int sum = 0;
while(bfs()) sum += dfs(st, 999999999);
ans = _max(ans, yy - sum + 1);
} put(ans);
return 0;
}