文章目录
传送门: here
https://wenku.baidu.com/view/85ec20aea417866fb94a8e99.html
https://blog.csdn.net/qq_28738419/article/details/80338544
M. Subsequence
可能数据比较水,暴力
1
e
8
∗
l
o
g
(
1
e
5
)
1e8*log(1e5)
1e8∗log(1e5)就行了。
其实可以先
26
∗
n
26*n
26∗n得预处理,然后
O
(
1
e
8
)
O(1e8)
O(1e8)就很稳了。
或者序列自动机。
#include<bits/stdc++.h>
#define eb push_back
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long LL;
const int MXN = 1e5 + 7;
int n, m;
std::vector<int> vs[28];
char ar[MXN], br[1003];
int main() {
scanf("%s", ar);
int len = strlen(ar);
for(int i = 0; i < len; ++i) {
vs[ar[i]-'a'].eb(i);
}
scanf("%d", &n);
int flag = 1, s = 0, p, tmp;
while(n --) {
scanf("%s", br);
m = strlen(br);
flag = 1, s = 0;
for(int i = 0; i < m; ++i) {
tmp = br[i]-'a';
if(vs[tmp].size() == 0 || vs[tmp].back() < s) {
flag = 0; break;
}
p = lower_bound(all(vs[tmp]), s) - vs[tmp].begin();
if(p == (int)vs[tmp].size()) {
flag = 0; break;
}
s = vs[tmp][p] + 1;
}
if(flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}
K. MORE XOR
利用fuck函数找出规律。
然后预处理4个异或值数组即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MXN = 5e5 + 6;
int n, m;
int ar[MXN], sum[MXN];
int f[105][105], g[105][105], w[105][105];
void fuck() {
for(int i = 1; i <= 12; ++i) {
ar[i] = 1LL<<(i-1);
}
n = 12;
for(int i = 1; i <= n; ++i) sum[i] = sum[i-1] ^ ar[i];
for(int i = 1; i <= n; ++i) {
for(int j = i; j <= n; ++j) f[i][j] = sum[j] ^ sum[i-1];
}
for(int i = 1; i <= n; ++i) {
for(int j = i; j <= n; ++j) {
for(int k = i; k <= j; ++k) {
for(int h = k; h <= j; ++h) {
g[i][j] ^= f[k][h];
}
}
}
}
for(int i = 1; i <= n; ++i) {
for(int j = i; j <= n; ++j) {
for(int k = i; k <= j; ++k) {
for(int h = k; h <= j; ++h) {
w[i][j] ^= g[k][h];
}
}
}
}
for(int i = 1; i <= n; ++i) {
printf("%d ", w[1][i]);
bitset<12> a(w[1][i]);
cout << a << endl;
}
printf("\n");
}
int A[MXN][4], B[MXN][4];
int main() {
//fuck();
int tim; scanf("%d", &tim);
while(tim --) {
scanf("%d", &n); ar[n+1] = 0;
for(int i = 1; i <= n; ++i) scanf("%d", &ar[i]);
A[1][0] = ar[1]; B[1][0] = ar[2];
for(int i = 2; i <= n; ++i) {
if(i % 4 == 1)A[i][0] = A[i - 1][0] ^ ar[i];
else A[i][0] = A[i - 1][0];
if(i % 4 == 1)B[i][0] = B[i - 1][0] ^ ar[i + 1];
else B[i][0] = B[i - 1][0];
}
A[1][1] = ar[2]; B[1][1] = ar[3];
for(int i = 2; i <= n; ++i) {
if(i % 4 == 2)A[i][1] = A[i - 1][1] ^ ar[i];
else A[i][1] = A[i - 1][1];
if(i % 4 == 2)B[i][1] = B[i - 1][1] ^ ar[i + 1];
else B[i][1] = B[i - 1][1];
}
A[1][2] = ar[3]; B[1][2] = ar[4];
for(int i = 2; i <= n; ++i) {
if(i % 4 == 3)A[i][2] = A[i - 1][2] ^ ar[i];
else A[i][2] = A[i - 1][2];
if(i % 4 == 3)B[i][2] = B[i - 1][2] ^ ar[i + 1];
else B[i][2] = B[i - 1][2];
}
A[1][3] = ar[4]; B[1][3] = ar[5];
for(int i = 2; i <= n; ++i) {
if(i % 4 == 0)A[i][3] = A[i - 1][3] ^ ar[i];
else A[i][3] = A[i - 1][3];
if(i % 4 == 0)B[i][3] = B[i - 1][3] ^ ar[i + 1];
else B[i][3] = B[i - 1][3];
}
int m; scanf("%d", &m);
while(m --) {
int l, r;
scanf("%d%d", &l, &r);
int len = r-l+1, p = len/4 + 1, ans = 0;
int id = l % 4;
if(id == 0) id = 3;
else -- id;
if(len % 4 == 0) {
printf("0\n");
}else if(len % 4 == 1) {
printf("%d\n", A[r][id]^A[l-1][id]);
}else if(len % 4 == 3) {
printf("%d\n", B[r][id]^B[l-1][id]);
}else {
printf("%d\n", A[r][id]^A[l-1][id]^B[r][id]^B[l-1][id]);
}
}
}
return 0;
}
J. Distance on the tree
这不是主席树裸题吗?
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int MXN = 2e5 + 7;
const int mod = 998244353;
int n, m, T, ALL;
int ar[MXN], br[MXN];
int up[MXN][22],dep[MXN];
struct lp {
int l, r, sum;
}cw[MXN*20];
int Root[MXN], tot_z;
struct node {
int v, nex, w;
}edge[MXN];
int head[MXN], tot_b;
void add_edge(int a, int b, int c) {
edge[++tot_b] = {b, head[a], c}; head[a] = tot_b;
edge[++tot_b] = {a, head[b], c}; head[b] = tot_b;
}
void update(int l, int r, int old, int &cur, int p) {
cw[++tot_z] = cw[old];
cur = tot_z;
++ cw[cur].sum;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(l,mid,cw[old].l,cw[cur].l,p);
else update(mid+1,r,cw[old].r,cw[cur].r,p);
}
void build(int u, int ba, int d, int w) {
if(w != -1) update(1, ALL, Root[ba], Root[u], w);
up[u][0] = ba; dep[u] = d; ar[u] = w;
for(int i = 1; i <= 20; ++i) up[u][i] = up[up[u][i-1]][i-1];
for(int i = head[u]; ~i; i = edge[i].nex) {
int v = edge[i].v;
if(v == ba) continue;
build(v, u, d + 1, edge[i].w);
}
}
int LCA(int x,int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = 20; i >= 0; --i) {
if(dep[up[x][i]] >= dep[y]) x = up[x][i];
}
if(x == y) return x;
for(int i = 20; i >= 0; --i) {
if(up[x][i] != up[y][i]) {
x = up[x][i], y = up[y][i];
}
}
return up[x][0];
}
int z_query(int l,int r,int u,int v,int lca,int k) {
if(l == r) return cw[u].sum+cw[v].sum-cw[lca].sum*2;
int mid = (l + r) >> 1;
if(k <= mid) return z_query(l,mid,cw[u].l,cw[v].l,cw[lca].l,k);
else {
int tmp = cw[cw[u].l].sum+cw[cw[v].l].sum-cw[cw[lca].l].sum*2;
return tmp + z_query(mid+1,r,cw[u].r,cw[v].r,cw[lca].r,k);
}
}
struct NODE {
int a, b, c;
}A[MXN];
int main() {
cw[0] = {0, 0, 0};
tot_b = -1; memset(head, -1, sizeof(head));
scanf("%d%d", &n, &m);
for(int i = 1, a, b, c; i < n; ++i) {
scanf("%d%d%d", &a, &b, &c);
A[i] = {a, b, c};
br[i] = c;
}
sort(br + 1, br + m);
ALL = unique(br + 1, br + m) - br;
for(int i = 0; i < m; ++i) {
A[i].c = lower_bound(br + 1, br + ALL, A[i].c) - br;
add_edge(A[i].a, A[i].b, A[i].c);
}
build(1, 0, 1, -1);
int x, y, z;
while(m --) {
scanf("%d%d%d", &x, &y, &z);
int lca = LCA(x, y);
int tmp = lower_bound(br + 1, br + ALL, z) - br;
if(tmp != ALL && br[tmp] != z) -- tmp;
x = Root[x], y = Root[y], lca = Root[lca];
//printf("tmp = %d %d %d %d\n", tmp, x, y, lca);
int ANS;
if(tmp == 0) ANS = 0;
else ANS = z_query(1, ALL, x, y, lca, tmp);
printf("%d\n", ANS);
}
return 0;
}
I. Max answer
复杂度:
O
(
n
l
o
g
(
n
)
)
O(nlog(n))
O(nlog(n))
按最小值位置分治。
对于正数找出左边得最小前缀,右边得最大前缀。
对于负数找出左边得最大前缀,右边得最小前缀。
还有一个细节看代码。
#include<bits/stdc++.h>
#define endl "\n"
#define fi first
#define se second
#define eb emplace_back
#define mk make_pair
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false);cin.tie(NULL);
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
typedef pair<int, LL> piL;
typedef vector<int> VI;
typedef vector<pii> VPII;
const int MXN = 1e6 + 6;
int n, m;
LL ar[MXN], sum[MXN];
struct TREE {
LL sum[MXN<<2];
int pos[MXN<<2], ip;//1小于0大于
void push_up(int rt) {
if(ip) {
if(sum[ls] <= sum[rs]) pos[rt] = pos[ls];
else pos[rt] = pos[rs];
sum[rt] = min(sum[ls], sum[rs]);
}else {
if(sum[ls] >= sum[rs]) pos[rt] = pos[ls];
else pos[rt] = pos[rs];
sum[rt] = max(sum[ls], sum[rs]);
}
}
void build(int l, int r, int rt, LL *a) {
if(l == r) {
sum[rt] = a[l];
pos[rt] = l;
return;
}
int mid = (l + r) >> 1;
build(l, mid, ls, a); build(mid+1, r, rs, a);
push_up(rt);
}
piL query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) return mk(pos[rt], sum[rt]);
int mid = (l + r) >> 1;
if(L > mid) return query(L, R, mid + 1, r, rs);
else if(R <= mid) return query(L, R, l, mid, ls);
else {
piL a = query(L, mid, l, mid, ls), b = query(mid + 1, R, mid + 1, r, rs);
if((ip && a.se <= b.se) || (ip == 0 && a.se > b.se)) return a;
else return b;
}
}
}cw1, cw2, cw3;//小大小
LL ans = -1e18;
void solve(int l, int r) {
if(l >= r) return ;
int mid = cw3.query(l, r, 1, n, 1).fi;
if(ar[mid] >= 0) {
LL a = cw1.query(l, mid, 1, n, 1).fi, b = cw2.query(mid, r, 1, n, 1).fi;
ans = max(ans, (sum[b]-sum[a-1])*ar[mid]);//细节
}else {
LL a = cw2.query(l, mid, 1, n, 1).fi, b = cw1.query(mid, r, 1, n, 1).fi;
ans = max(ans, (sum[b]-sum[a])*ar[mid]);//细节
}
solve(l, mid-1); solve(mid + 1, r);
}
void init() {
cw1.ip = cw3.ip = 1; cw2.ip = 0;
cw1.build(1, n, 1, sum);
cw2.build(1, n, 1, sum);
cw3.build(1, n, 1, ar);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%lld", &ar[i]);
ans = max(ans, ar[i]*ar[i]);
sum[i] = sum[i-1] + ar[i];
}
init();
solve(1, n);
printf("%lld\n", ans);
return 0;
}
C. Angry FFF Party
矩阵快速幂预处理。
然后大的暴力,小的状压预处理一下就行了。
对于大于
21
21
21的
W
W
W,能选大的一定要先选大的,不然就凑不齐了。
c l s cls cls说可以取模做? o r z orz orz
import com.sun.org.apache.bcel.internal.generic.BIPUSH;
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static class mat{
BigInteger[][] ar = new BigInteger[3][3];
}
static mat exe(mat a, mat b) {
mat c = new mat();
c.ar[0][0] = BigInteger.ZERO;c.ar[0][1] = BigInteger.ZERO;c.ar[1][0] = BigInteger.ZERO;c.ar[1][1] = BigInteger.ZERO;
for(int k = 0; k < 2; ++k) {
for(int i = 0; i < 2; ++i) {
for(int j = 0; j < 2; ++j) {
c.ar[i][j] = c.ar[i][j].add(a.ar[i][k].multiply(b.ar[k][j]));
}
}
}
return c;
}
static mat ksm(mat a, int b) {
mat res = new mat();
for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) res.ar[i][j] = BigInteger.valueOf(i==j?1:0);
while(b > 0) {
if(b%2 == 1) res = exe(res, a);
a = exe(a, a);
b /= 2;
}
return res;
}
public static void main(String[] args) {
int[] f = new int[35];
BigInteger[] g = new BigInteger[35];
f[1] = 1; f[2] = 1;
for(int i = 3; i <= 30; ++i) f[i] = f[i-1] + f[i-2];
mat a = new mat(), b = new mat();
a.ar[0][0] = BigInteger.ONE;a.ar[0][1] = BigInteger.ONE;a.ar[1][0] = BigInteger.ZERO;a.ar[1][1] = BigInteger.ZERO;
b.ar[0][0] = BigInteger.ONE;b.ar[0][1] = BigInteger.ONE;b.ar[1][0] = BigInteger.ONE;b.ar[1][1] = BigInteger.ZERO;
g[1] = BigInteger.ONE; g[2] = BigInteger.ONE; g[3] = BigInteger.ONE;
for(int i = 4; i <= 30; ++i) {
b.ar[0][0] = BigInteger.ONE;b.ar[0][1] = BigInteger.ONE;b.ar[1][0] = BigInteger.ONE;b.ar[1][1] = BigInteger.ZERO;
//System.out.println(f[i]);
b = ksm(b, f[i]-2);
b = exe(a, b);
g[i] = b.ar[0][0];
}
Scanner cin = new Scanner(System.in);
int tim = cin.nextInt(), n;
BigInteger w = new BigInteger("0");
while(tim != 0) {
tim --;
w = cin.nextBigInteger();
int flag = 1, s = 30;
int cnt = 0;
int[] ans = new int[35];
while(true) {
if(w.compareTo(BigInteger.valueOf(21)) < 0) {
break;
}
int p = -1;
for(int i = s; i >= 1; --i) {
if(w.compareTo(g[i]) >= 0) {
p = i; break;
}
}
if(p == -1) {
flag = 0; break;
}
w = w.subtract(g[p]);
ans[cnt] = p; ++ cnt;
s = p - 1;
if(w.compareTo(BigInteger.ZERO) == 0) {
break;
}
if(s == 0) {
flag = 0; break;
}
}
if(flag == 0) {
System.out.println(-1);
}else if(w.compareTo(BigInteger.ZERO) == 0){
for(int i = cnt-1; i >= 0; --i) {
if(i == 0) System.out.println(ans[i]);
else System.out.print(ans[i] + " ");
}
}else {
int sta = 1 << s, ANS = 0;
for(int i = 1; i < sta; ++i) {
BigInteger tmp = BigInteger.ZERO;
for(int j = 0; j < s; ++j) {
if((i&(1<<j)) != 0) {
tmp = tmp.add(g[j+1]);
}
}
if(tmp.compareTo(w) == 0) {
flag = -1;
ANS = i;
break;
}
}
if(flag == -1) {
for(int j = s-1; j >= 0; --j) {
if((ANS&(1<<j)) != 0) {
ans[cnt] = j+1; ++ cnt;
}
}
for(int i = cnt-1; i >= 0; --i) {
if(i == 0) System.out.println(ans[i]);
else System.out.print(ans[i] + " ");
}
}else {
System.out.println(-1);
}
}
}
}
}
D.Match Stick Game
d
p
1
[
i
]
[
j
]
dp1[i][j]
dp1[i][j]:
i
i
i个棒子形成
j
j
j位数的最大数字
d
p
2
[
i
]
[
j
]
dp2[i][j]
dp2[i][j]:
i
i
i个棒子形成
j
j
j位数的最小数字
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]:
i
i
i个火柴组成前
j
j
j项的表达式的最大值
转移就是:枚举这一项前面的符号是正号还是负号
#include<bits/stdc++.h>
#define endl "\n"
#define fi first
#define se second
#define eb emplace_back
#define mk make_pair
#define all(x) (x).begin(), (x).end()
#define clr(a, b) memset((a),(b),sizeof((a)))
#define iis std::ios::sync_with_stdio(false);cin.tie(NULL);
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
typedef vector<int> VI;
typedef vector<pii> VPII;
const LL INFLL = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
const int MOD = 998244353;
const int MXE = 2e6 + 6;
const int MXN = 1e3 + 6;
int n, m;
char s[MXN];
int ar[MXN], br[MXN], wei[MXN];
int is[20] = {6,2,5,5,4,5,6,3,7,6};
LL dp1[MXN][15], dp2[MXN][15];//大小
//dp1[i][j]i个棒子j位数的最大数字
LL dp[MXN][MXN];//i个火柴组成前j项的表达式的最大值
int get_wei(int x) {
int cnt = 0;
while(x) {
++ cnt; x /= 10;
}
return cnt;
}
/*
1 2 3 4 5 6 7 8 9 0
2 5 5 4 5 6 3 7 6 6
*/
void init() {
memset(dp2, 0x3f, sizeof(dp2));
int all = 701;
dp2[0][0] = 0;
for(int i = 2; i <= all; ++i) {
for(int j = 1; j <= 10; ++j) {
dp1[i][j] = max(dp1[i][j], dp1[i-2][j-1] * 10 + 1);
if(i >= 3) dp1[i][j] = max(dp1[i][j], dp1[i-3][j-1] * 10 + 7);
if(i >= 4) dp1[i][j] = max(dp1[i][j], dp1[i-4][j-1] * 10 + 4);
if(i >= 5) dp1[i][j] = max(dp1[i][j], dp1[i-5][j-1] * 10 + 5);
if(i >= 6) dp1[i][j] = max(dp1[i][j], dp1[i-6][j-1] * 10 + 9);
if(i >= 7) dp1[i][j] = max(dp1[i][j], dp1[i-7][j-1] * 10 + 8);
dp2[i][j] = min(dp2[i][j], dp2[i-2][j-1] * 10 + 1);
if(i >= 3) dp2[i][j] = min(dp2[i][j], dp2[i-3][j-1] * 10 + 7);
if(i >= 4) dp2[i][j] = min(dp2[i][j], dp2[i-4][j-1] * 10 + 4);
if(i >= 5) dp2[i][j] = min(dp2[i][j], dp2[i-5][j-1] * 10 + 2);
if(i >= 6 && (j == 1 || dp2[i-6][j-1] != 0)) dp2[i][j] = min(dp2[i][j], dp2[i-6][j-1] * 10 + 0);
if(i >= 7) dp2[i][j] = min(dp2[i][j], dp2[i-7][j-1] * 10 + 8);
}
}
}
int main() {
init();
int tim; scanf("%d", &tim);
while(tim --) {
scanf("%d%s", &n, s);
int m = 0, cnt = 0;
int all = 0;
for(int i = 0; i < n; ++i) {
if(isdigit(s[i])) all += is[s[i]-'0'];
else if(s[i] == '+') all += 2;
else if(s[i] == '-') ++ all;
if(isdigit(s[i]) && i != n - 1) cnt = cnt * 10 + s[i] - '0';
else {
if(i == n-1) cnt = cnt * 10 + s[i] - '0';
ar[m++] = cnt;
cnt = 0;
br[m-1] = (s[i]=='+');
}
}
for(int i = 0; i < m; ++i) wei[i+1] = get_wei(ar[i]);
//for(int i = 0; i < m-1; ++i) printf("%d\n", br[i]);
//printf("**\n");
memset(dp, -1, sizeof(dp));
for(int i = 2; i <= all; ++i) dp[i][1] = dp1[i][wei[1]];
//printf("[%d]\n", dp[3][1]);
for(int i = 5; i <= all; ++i) {
for(int j = 2; j <= m; ++j) {
for(int k = 2; k <= i-2; ++k) {
if(dp[i-2-k][j-1]!=-1)dp[i][j] = max(dp[i][j], dp[i-2-k][j-1] + dp1[k][wei[j]]);
}
for(int k = 2; k <= i-1; ++k) {
if(dp[i-1-k][j-1]!=-1)dp[i][j] = max(dp[i][j], dp[i-1-k][j-1] - dp2[k][wei[j]]);
}
}
}
/*
1 2 3 4 5 6 7 8 9 0
2 5 5 4 5 6 3 7 6 6
*/
//printf("[%d] [%d]\n", dp[3][1], dp[5][2]);
printf("%lld\n", dp[all][m]);
}
return 0;
}