2019 ICPC南昌邀请赛网络赛部分题解
A.
题目:https://nanti.jisuanke.com/t/38220
题意:求前5个因子和等于它本身的数(不算自身)
线性筛
[code]#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N = 4e6 + 100; int prime , f , fu , tot; bool is_prime ; void init() { memset(is_prime, true , sizeof(is_prime)); for (int i = 2; i < N; i++) { if (is_prime[i]) { prime[tot++] = i; f[i] = 1 + i; fu[i] = i; } for (int j = 0; j < tot && i * prime[j] < N; j++) { is_prime[i * prime[j]] = false; if (i % prime[j] == 0) { fu[i * prime[j]] = fu[i] * prime[j]; if (fu[i] == i) { f[i * prime[j]] = f[i] + i * prime[j]; }else { f[i * prime[j]] = f[i / fu[i]] * f[fu[i] * prime[j]]; } break; }else { fu[i * prime[j]] = prime[j]; f[i * prime[j]] = f[i] * f[prime[j]]; } } if (f[i] == i * 2) printf("%d\n", i); } } int main() { puts("6"); puts("28"); puts("496"); puts("8128"); puts("33550336"); return 0; }
C.
题目:https://nanti.jisuanke.com/t/38222
题意:f(x)是斐波那契数的第x项,g(x)=f(f(x)),对于给定的n,将其表示成若干个g数的和,要求字典序最小,n<10^100000
矩阵快速幂求一下f(x),预处理前29项g(x)。
可以发现g(x)的增长速度非常快,其实在第29项就已经超出10^100000,由于后面的项差过大,所以方法基本唯一,所以就把贪心选一下,然后前几项在特判一下取个最小字典序就ok了。
[code]import java.io.*; import java.math.*; import java.util.*; public class Main { static int maxn = 29; static BigInteger []w = new BigInteger[maxn]; static int []v = new int[maxn]; public static BigInteger f(BigInteger n){ n = n.subtract(BigInteger.ONE); BigInteger [][]a = new BigInteger[2][2]; BigInteger [][]b = new BigInteger[2][2]; BigInteger [][]c = new BigInteger[2][2]; for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) a[i][j] = BigInteger.ZERO; a[0][0] = a[1][0] = a[0][1] = BigInteger.ONE; for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++) b[i][j] = BigInteger.ZERO; for(int i = 0; i < 2; i++) b[i][i] = BigInteger.ONE; while(n.compareTo(BigInteger.ZERO) > 0){ if(n.mod(new BigInteger("2")).equals(BigInteger.ONE)){ for(int i = 0; i < 2; i++){ for(int j = 0; j < 2; j++){ c[i][j] = BigInteger.ZERO; for(int k = 0; k < 2; k++){ c[i][j] = c[i][j].add(b[i][k].multiply(a[k][j])); } } } for(int i = 0; i < 2; i++){ for(int j = 0; j < 2; j++){ b[i][j] = c[i][j]; } } } for(int i = 0; i < 2; i++){ for(int j = 0; j < 2; j++){ c[i][j] = BigInteger.ZERO; for(int k = 0; k < 2; k++){ c[i][j] = c[i][j].add(a[i][k].multiply(a[k][j])); } } } for(int i = 0; i < 2; i++){ for(int j = 0; j < 2; j++){ a[i][j] = c[i][j]; } } n = n.divide(new BigInteger("2")); } //System.out.println("len " + b[0][0].toString().length()); return b[0][0]; } public static void main(String[] args) { Scanner cin = new Scanner (System.in); for(int i = 1; i < maxn; i++){ w[i] = f(f(BigInteger.valueOf(i))); } // System.out.println(w[6] + " " + w[7]); int T = cin.nextInt(); while(T > 0){ T--; BigInteger n = cin.nextBigInteger(); int tot = 0; for(int i = maxn - 1; i > 0; i--){ if(n.equals(new BigInteger("5")) && i >= 4){ v[tot++] = 4; v[tot++] = 3; v[tot++] = 2; v[tot++] = 1; n = BigInteger.ZERO; break; } if(n.equals(new BigInteger("4")) && i >= 4){ v[tot++] = 4; v[tot++] = 2; v[tot++] = 1; n = BigInteger.ZERO; break; } if(n.equals(new BigInteger("3")) && i >= 3){ v[tot++] = 3; v[tot++] = 2; v[tot++] = 1; n = BigInteger.ZERO; break; } if(n.equals(new BigInteger("2")) && i >= 2){ v[tot++] = 2; v[tot++] = 1; n = BigInteger.ZERO; break; } if(n.equals(new BigInteger("1")) && i >= 1){ v[tot++] = 1; n = BigInteger.ZERO; break; } if(n.compareTo(w[i]) >= 0){ v[tot++] = i; n = n.subtract(w[i]); } } if(!n.equals(BigInteger.ZERO)) System.out.println(-1); else{ for(int i = tot - 1; i >= 0; i--) System.out.printf("%d%c", v[i], i == 0 ? '\n' : ' '); } } cin.close(); } }
D.
题目:https://nanti.jisuanke.com/t/38223
先将表达式表示成用最少火柴棍能表达的形式,然后在此基础上添加火柴棍。
先预处理出i位数添加j个火柴棍能够得到的最大值,然后背包一下就ok了。
举个例子
1+1+222
最简表示1-1-111,剩余11根棒子。
一共三项,1,-1,-111,然后dp[i][j]表示前i项加j根棒子的和的最大值,转移显然。
关键是预处理比较麻烦,见代码吧。
[code]#include <bits/stdc++.h> #define my_max(a, b) ((a) > (b) ? (a) : (b)) #define my_min(a, b) ((a) < (b) ? (a) : (b)) #define fi first #define se second #define pb push_back #define eb emplace_back #define rep(i, s, t) for(int i = (int)(s); i <= (int)(t); i++) #define rev(i, t, s) for(int i = (int)(t); i >= (int)(s); i--) #define lson rt << 1 #define rson rt << 1 | 1 #define sz(x) (int)(x).size() typedef long long ll; typedef long double lb; typedef std::pair<int, int> pii; typedef std::pair<ll, ll> pll; typedef std::vector<int> VI; typedef std::vector<ll> VL; #include <ext/pb_ds/tree_policy.hpp> #include <ext/pb_ds/assoc_container.hpp> using namespace __gnu_pbds; using namespace std; typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> rbtree; ll gcd(ll x, ll y){ return y % x == 0 ? x : gcd(y % x, x); } template<class T>T my_abs(T a){ if(a < 0) a = -a; return a; } inline ll read(){ ll ret = 0, sign = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar();} while(c >= '0' && c <= '9'){ ret = ret * 10 + c - '0'; c = getchar(); } return ret * sign; } inline void write(ll x){ if(x < 0){ putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } //void expand_stack_space(){ // int size = 256 << 20; // 256MB // char *p = (char*)malloc(size) + size; // __asm__("movl %0, %%esp\n" :: "r"(p)); //} const int maxn = 100 + 7; const ll inf = 1e18; ll dp[maxn][maxn * 10], sa[maxn]; ll a[maxn][maxn], b[maxn][maxn]; int n; char str[maxn]; int count(char c){ if(c == '-' || c == '1') return 0; if(c == '7' || c == '+') return 1; if(c == '4') return 2; if(c == '2' || c == '3' || c == '5') return 3; if(c == '0' || c == '6' || c == '9') return 4; if(c == '8') return 5; } char icount(int c){ if(c == 1) return '7'; if(c == 2) return '4'; if(c == 3) return '5'; if(c == 4) return '9'; if(c == 5) return '8'; } void init(){ for(int i = 1; i <= 10; i++){ for(int j = 0; j <= 5 * i; j++){ int c = j; string s = ""; for(int k = 1; k <= i; k++){ if(c >= count('9')) s += '9', c -= count('9'); else if(c >= count('7')) s += '7', c -= count('7'); else s += '1'; } for(int k = i; k >= 1; k--){ if(c == 0) break; c += count(s[k - 1]); if(c >= count('8')) s[k - 1] = '8', c -= count('8'); else{ s[k - 1] = icount(c); c = 0; } } ll res = 0; //cout<<"s " + s<<endl; for(char ss : s) res = res * 10 + ss - '0'; a[i][j] = res; b[i][j + 1] = res; } b[i][0] = -b[i][1]; } } int main(){ #ifndef ONLINE_JUDGE // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int T; init(); scanf("%d", &T); while(T--){ scanf("%d", &n); scanf("%s", str); int cnt = 0; for(int i = 0; i < n; i++) cnt += count(str[i]); int num = 0, tot = 0; for(int i = 0; i < n; i++){ if(str[i] == '-' || str[i] == '+'){ sa[++tot] = num; num = 0; } else num++; } //printf("cnt %d\n", cnt); sa[++tot] = num; for(int i = 0; i <= tot; i++) for(int j = 0; j <= cnt; j++) dp[i][j] = -inf; //比赛时初始化写错了, 还过了。emmmm dp[0][0] = 0; for(int i = 1; i <= tot; i++){ int len = sa[i]; //printf("len %d\n", len); if(i == 1){ for(int k = 0; k <= 5 * len; k++){ for(int j = cnt; j >= k; j--){ dp[i][j] = max(dp[i][j], dp[i - 1][j - k] + a[len][k]); } } } else{ for(int k = 0; k <= 5 * len; k++){ for(int j = cnt; j >= k; j--){ dp[i][j] = max(dp[i][j], dp[i - 1][j - k] + b[len][k]); } } } } printf("%lld\n", dp[tot][cnt]); } return 0; }
G.
题目:https://nanti.jisuanke.com/t/38226
题解:
[code]#include <cstdio> #include <algorithm> #include <cstring> #include <iostream> using namespace std; typedef unsigned int ll; const int N = 1e7 + 10; int prime , phi , tot; ll f , gg , fu , res ; bool is_prime ; void init() { memset(is_prime, true, sizeof(is_prime)); for (ll i = 1; i < N; i++) f[i] = f[i - 1] + 1; for (ll i = 1; i < N; i++) { gg[i] = gg[i - 1] + i; f[i] = f[i] * gg[i]; } for (ll i = 1; i < N; i++) { gg[i] = gg[i - 1] + i * i; f[i] = f[i] * gg[i]; } phi[1] = gg[1] = fu[1] = 1; for (int i = 2; i < N; i++) { if (is_prime[i]) { prime[tot++] = i; fu[i] = i; phi[i] = i - 1; gg[i] = i - 2; } for (int j = 0; j < tot && i * prime[j] < N; j++) { is_prime[i * prime[j]] = false; if (i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; fu[i * prime[j]] = fu[i] * prime[j]; if (fu[i] == i) { gg[i * prime[j]] = phi[i * prime[j]] - phi[i]; }else { gg[i * prime[j]] = gg[i / fu[i]] * gg[fu[i * prime[j]]]; } break; }else { fu[i * prime[j]] = prime[j]; phi[i * prime[j]] = phi[i] * phi[prime[j]]; gg[i * prime[j]] = gg[i] * gg[prime[j]]; } } } for (ll i = 1; i < N; i++) { res[i] = i * i * i * gg[i] + res[i - 1]; } } int n; void solve() { ll ans = 0; for (ll l = 1, r; l <= n; l = r + 1) { r = n / (n / l); ans += (res[r] - res[l - 1]) * f[n / l]; } printf("%d\n", ans % (1 << 30)); } int main() { //freopen("0in.txt", "r", stdin); init(); int T; scanf("%d", &T); while (T--) { scanf("%d", &n); solve(); } return 0; }
H.
题目:https://nanti.jisuanke.com/t/38227
两端两种,中间三种。特判n=1。
[code]#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e9 + 7; ll quick_mod(ll n,ll x) { ll res=1; while(x) { if(x&1) res=res*n%mod; n=n*n%mod; x>>=1; } return res; } int main() { ll n; cin>>n; if(n==1) cout<<1<<endl; else cout<<quick_mod(3,n-2)*4%mod<<endl; return 0; }
I.
题目:https://nanti.jisuanke.com/t/38228
题意:给一个长为n(n <= 500000)的数组a, 对每个区间,求区间和乘区间最小值的最大值
先用单调栈求出以a[i]为最小值能够延伸的左端点L[i]和右端点R[i],然后求前缀和,建立一颗线段树。对于每个位置i,求出[L[i] - 1,i]前缀和的最大值Maxl、最小值Minl和[i, R[i]]的最大值Maxr、最小值Minr。这样就可以查询到以a[i]为最小值的区间的和的最大值和最小值。然后枚举最小值a[i]即可。
[code]#include <bits/stdc++.h> #define my_max(a, b) ((a) > (b) ? (a) : (b)) #define my_min(a, b) ((a) < (b) ? (a) : (b)) #define fi first #define se second #define pb push_back #define eb emplace_back #define rep(i, s, t) for(int i = (int)(s); i <= (int)(t); i++) #define rev(i, t, s) for(int i = (int)(t); i >= (int)(s); i--) #define lson rt << 1 #define rson rt << 1 | 1 #define sz(x) (int)(x).size() typedef long long ll; typedef long double lb; typedef std::pair<int, int> pii; typedef std::pair<ll, ll> pll; typedef std::vector<int> VI; typedef std::vector<ll> VL; #include <ext/pb_ds/tree_policy.hpp> #include <ext/pb_ds/assoc_container.hpp> using namespace __gnu_pbds; using namespace std; typedef tree< 20000 ;int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> rbtree; ll gcd(ll x, ll y){ return y % x == 0 ? x : gcd(y % x, x); } template<class T>T my_abs(T a){ if(a < 0) a = -a; return a; } inline ll read(){ ll ret = 0, sign = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar();} while(c >= '0' && c <= '9'){ ret = ret * 10 + c - '0'; c = getchar(); } return ret * sign; } inline void write(ll x){ if(x < 0){ putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } //void expand_stack_space(){ // int size = 256 << 20; // 256MB // char *p = (char*)malloc(size) + size; // __asm__("movl %0, %%esp\n" :: "r"(p)); //} const int maxn = 5e5 + 7; const ll inf = 1e18; int n; struct SegmentTree{ ll Max[maxn << 2], Min[maxn << 2]; void init(ll *a){ build(1, 1, n, a); } void push_up(int rt){ Min[rt] = min(Min[lson], Min[rson]); Max[rt] = max(Max[lson], Max[rson]); } void build(int rt, int l, int r, ll *a){ if(l == r){ Max[rt] = Min[rt] = a[l]; return ; } int mid = (l + r) >> 1; build(lson, l, mid, a); build(rson, mid + 1, r, a); push_up(rt); } ll queryMin(int ql, int qr, int rt = 1, int l = 1, int r = n){ if(ql == l && qr == r) return Min[rt]; int mid = (l + r) >> 1; ll res = inf; if(qr <= mid) res = queryMin(ql, qr, lson, l, mid); else if(ql > mid) res = queryMin(ql, qr, rson, mid + 1, r); else{ res = min(queryMin(ql, mid, lson, l, mid), queryMin(mid + 1, qr, rson, mid + 1, r)); } return res; } ll queryMax(int ql, int qr, int rt = 1, int l = 1, int r = n){ if(ql == l && qr == r) return Max[rt]; int mid = (l + r) >> 1; ll res = -inf; if(qr <= mid) res = queryMax(ql, qr, lson, l, mid); else if(ql > mid) res = queryMax(ql, qr, rson, mid + 1, r); else{ res = max(queryMax(ql, mid, lson, l, mid), queryMax(mid + 1, qr, rson, mid + 1, r)); } return res; } }pre; ll presum[maxn], a[maxn]; int L[maxn], R[maxn], st[maxn], top; int main(){ #ifndef ONLINE_JUDGE // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE scanf("%d", &n); presum[1] = 0; for(int i = 2; i <= n + 1; i++){ scanf("%lld", a + i); presum[i] = presum[i - 1] + a[i]; } top = 0; for(int i = 2; i <= n + 1; i++){ while(top > 0 && a[st[top]] >= a[i]) top--; if(top > 0) L[i] = st[top] + 1; else L[i] = 1; st[++top] = i; } top = 0; for(int i = n + 1; i >= 2; i--){ while(top > 0 && a[st[top]] >= a[i]) top--; if(top > 0) R[i] = st[top] - 1; else R[i] = n + 1; st[++top] = i; } n++; pre.init(presum); ll ans = -inf; for(int i = 2; i <= n; i++){ int l = L[i], r = R[i]; l = max(l - 1, 1); // printf("i %d L %d R %d\n", i, l, r); ll Maxl = pre.queryMax(l, i), Minl = pre.queryMin(l, i); ll Maxr = pre.queryMax(i, r), Minr = pre.queryMin(i, r); ll ans1 = (Maxr - Minl) * a[i]; ll ans2 = (Minr - Maxl) * a[i]; //printf("Max %lld Min %lld\n", Maxr - Minl, Minr - Maxl); // printf("ans1 %lld ans2 %lld\n", ans1, ans2); ans1 = max(ans1, ans2); ans1 = max(ans1, a[i] * a[i]); ans = max(ans, ans1); } printf("%lld\n", ans); return 0; }
J.
题目:https://nanti.jisuanke.com/t/38229
题意:给一棵n(n <= 100000)个结点的树,q(q <= 100000)次询问,询问u到v的路径上边权小于等于k的边的数量
主席树+LCA,dfs一次从根向下建主席树,每次查询结点到根的路径上边权小于等于k的数的数量,令cnt(u)为u到根的路径上边权小于等于k的数的数量,则答案ans = cnt(u) + cnt(v) - 2 * cnt(lca(u, v))。也可以离线用树状数组实现。
[code]#include <bits/stdc++.h> #define my_max(a, b) ((a) > (b) ? (a) : (b)) #define my_min(a, b) ((a) < (b) ? (a) : (b)) #define fi first #define se second #define pb push_back #define eb emplace_back #define rep(i, s, t) for(int i = (int)(s); i <= (int)(t); i++) #define rev(i, t, s) for(int i = (int)(t); i >= (int)(s); i--) #define lson rt << 1 #define rson rt << 1 | 1 #define sz(x) (int)(x).size() typedef long long ll; typedef long double lb; typedef std::pair<int, int> pii; typedef std::pair<ll, ll> pll; typedef std::vector<int> VI; typedef std::vector<ll> VL; #include <ext/pb_ds/tree_policy.hpp> #include <ext/pb_ds/assoc_container.hpp> using namespace __gnu_pbds; using namespace std; typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> rbtree; ll gcd(ll x, ll y){ return y % x == 0 ? x : gcd(y % x, x); } template<class T>T my_abs(T a){ if(a < 0) a = -a; return a; } inline ll read(){ ll ret = 0, sign = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar();} while(c >= '0' && c <= '9'){ ret = ret * 10 + c - '0'; c = getchar(); } return ret * sign; } inline void write(ll x){ if(x < 0){ putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } //void expand_stack_space(){ // int size = 256 << 20; // 256MB // char *p = (char*)malloc(size) + size; // __asm__("movl %0, %%esp\n" :: "r"(p)); //} const int maxn = 1e5 + 7; int root[maxn], fa[maxn][20], cnt, dep[maxn]; int sum[maxn * 50]; vector<int> num; vector<pii> G[maxn]; struct node{ int ls, rs; }Tree[maxn * 50]; int find(int x){ return lower_bound(num.begin(), num.end(), x) - num.begin() + 1; } void insert(int old_k, int &new_k, int pos, int l, int r){ new_k = ++cnt; Tree[new_k] = Tree[old_k]; sum[new_k] = sum[old_k]; sum[new_k]++; if(l == r) return ; int mid = (l + r) >> 1; if(pos <= mid) insert(Tree[old_k].ls, Tree[new_k].ls, pos, l, mid); else insert(Tree[old_k].rs, Tree[new_k].rs, pos, mid + 1, r); } int query(int rt, int l, int r, int ql, int qr){ if(l == ql && r == qr) return sum[rt]; int mid = (l + r) >> 1; int res = 0; if(qr <= mid) res += query(Tree[rt].ls, l, mid, ql, qr); else if(ql > mid) res += query(Tree[rt].rs, mid + 1, r, ql, qr); else{ res += query(Tree[rt].ls, l, mid, ql, mid); res += query(Tree[rt].rs, mid + 1, r, mid + 1, qr); } return res; } void dfs(int u, int f){ fa[u][0] = f; dep[u] = dep[f] + 1; for(int i = 1; i <= 19; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for(pii &p : G[u]){ if(p.fi != f){ insert(root[u], root[p.fi], p.se, 1, sz(num)); dfs(p.fi, u); } } } int lca(int u, int v){ if(dep[u] > dep[v]) swap(u, v); int k = dep[v] - dep[u]; for(int i = 0; i <= 19; i++){ if((k >> i) & 1) v = fa[v][i]; } if(u == v) return u; for(int i = 19; i >= 0; i--){ if(fa[u][i] != fa[v][i]){ u = fa[u][i]; v = fa[v][i]; } } return fa[u][0]; } int n, m, up[maxn], vp[maxn], wp[maxn]; int main(){ #ifndef ONLINE_JUDGE // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE scanf("%d%d", &n, &m); for(int i = 1; i < n; i++){ scanf("%d%d%d", up + i, vp + i, wp + i); num.push_back(wp[i]); } sort(num.begin(), num.end()); num.erase(unique(num.begin(), num.end()), num.end()); for(int i = 1; i < n; i++){ wp[i] = find(wp[i]); G[up[i]].push_back(pii(vp[i], wp[i])); G[vp[i]].push_back(pii(up[i], wp[i])); } dfs(1, 0); for(int i = 1; i <= m; i++){ int u, v, k; scanf("%d%d%d", &u, &v, &k); int LCA = lca(u, v); k = upper_bound(num.begin(), num.end(), k) - num.begin() + 1; k--; k = min(k, sz(num)); if(k == 0) puts("0"); else{ int ucnt = query(root[u], 1, sz(num), 1, k); int vcnt = query(root[v], 1, sz(num), 1, k); int LCAcnt = query(root[LCA], 1, sz(num), 1, k); int ans = ucnt + vcnt - 2 * LCAcnt; printf("%d\n", ans); } } return 0; }
K.
题目:https://nanti.jisuanke.com/t/38230
枚举长度,对于每个数可以算贡献,也可以打表找规律,结果都是一样的,能够发现每个数是否选取是对于区间长度%4的循环。
[code]#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; int a[maxn]; int p[maxn][4]; int main() { int t; scanf("%d",&t); while(t--) { int n,l,r; scanf("%d",&n); memset(a,0,sizeof(a)); memset(p,0,sizeof(p)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); for(int j=0;j<4;j++) p[i][j]=p[i-1][j]; p[i][i%4]^=a[i]; } int q; scanf("%d",&q); while(q--) { scanf("%d%d",&l,&r); int len=(r-l+1)%4; if(len==0) printf("0\n"); if(len==1) printf("%d\n",p[r][l%4]^p[l-1][l%4]); if(len==2) printf("%d\n",p[r][l%4]^p[l-1][l%4]^p[r][(l+1)%4]^p[l-1][(l+1)%4]); if(len==3) printf("%d\n",p[r][(l+1)%4]^p[l-1][(l+1)%4]); } } return 0; }
M.
题目:https://nanti.jisuanke.com/t/38232
题意:给一个主串S,询问n次,每次给出一个串Ti,问Ti是否为S的子序列。
用nxt[i][c]记录位置i后c第一次出现的位置。查询直接往后跳即可。
[code]#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N = 1e5 + 100; const int M = 26; int n, m, L; int nex [M]; char str ; void init() { memset(nex, 0x3f3f3f3f, sizeof(nex)); L = strlen(str); for (int i = L - 1; i >= 0; i--) { for (int j = 0; j < 26; j++) { if (str[i] - 'a' == j) nex[i][j] = i; else nex[i][j] = nex[i + 1][j]; } } } int main() { //freopen("0in.txt", "r", stdin); scanf("%s", str); init(); scanf("%d", &n); while (n--) { scanf("%s", str); int len = strlen(str); int p = -1; for (int i = 0; i < len && p < L; i++) { p = nex[p + 1][str[i] - 'a']; } if (p < L) puts("YES"); else puts("NO"); } return 0; }
- 哈尔滨理工大学软件学院ACM程序设计全国邀请赛(网络同步赛【部分题解】)
- The 2014 ACM-ICPC Asia Mudanjiang Regional Contest 【部分题解】
- 2017 ACM/ICPC Asia Regional Shenyang Online(部分题解)
- The 2018 ACM-ICPC Asia Qingdao Regional Contest(部分题解)
- 2016 acm/icpc 青岛网络赛 题解(hdu 5878-5889,9道题)
- 2018 青岛网络赛部分题解
- 2014北京邀请赛(部分题解)
- 2016广东工业大学新生杯决赛网络同步赛暨全国新生邀请赛 题解&源码
- HDU-2017中国大学生程序设计竞赛-网络选拔赛-部分题解及代码
- 2014 ACM/ICPC牡丹江区域赛部分题解
- uva 7008 The 2014 ACM-ICPC Asia Mudanjiang Regional Contest 【部分题解】
- 2014北京邀请赛(部分题解)
- 2016 ACM/ICPC亚洲区青岛站现场赛(部分题解)
- “亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛 (部分题解)
- 2018-2019 ACM-ICPC, Asia Shenyang Regional Contest 一些题解
- own problem, ICPC Asia regionals, Amritapuri 2010 部分题解
- ACM-ICPC 2018 徐州赛区网络预赛(部分
- 2018-2019 ACM-ICPC, Asia Nanjing Regional Contest 一些题解
- 2018-2019 ICPC, NEERC, Northern Eurasia Finals 一些题解
- 计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛-总结及部分代码