过了n天补的题解:D
AB就不用说了
C. Obtain The String
思路挺简单的,就是贪心,但是直接贪心的复杂度是O(|s|*|t|),会超时,所以需要用到序列自动机
虽然名字很高端但是就是个数组啦(不过我自己想不到就是了)
next[i][j]表示i之后第一次出现j字符的位置,用这个函数就可以把复杂度降到O(|t|)
#include <cstdio> #include <cstring> using namespace std; const int N = 100010; char s[N], t[N]; bool flag[30]; int next[N][30]; int main() { int cs; scanf("%d", &cs); while (cs--) { scanf("%s", s); scanf("%s", t); int len1 = strlen(t); int len2 = strlen(s); int l = 0, cnt = 1; memset(next, 0xff, sizeof(next)); for (int i = len2 - 1; i >= 0; i--) { for (int j = 0; j < 26; j++) next[i][j] = next[i + 1][j]; next[i][s[i] - 'a'] = i; //递推式很简单 } int pos = 0; for (int i = 0; i < len1; i++) { pos = next[pos][t[i] - 'a'] + 1; if (pos == 0) { cnt++; pos = next[0][t[i] - 'a'] + 1; if (pos == 0) { cnt = -1; break; } } } printf("%d\n", cnt); } return 0; }
D.Same GCDs
如果知道了gcd(a, b) = gcd(a - b, b) (a > b)就是欧拉函数模板题,可惜不知道
gcd(a, m) = gcd(a + x, m) = k
gcd(a/k, m/k) = gcd(a/k + b, m/k) = 1
刚好就是phi[m/k]的值
#include <cstdio> using namespace std; long long gcd(long long a, long long b) { return (a % b == 0) ? b : gcd(b, a % b); } long long GetPhi(long long a) { long long res = a; for (long long i = 2; i * i <= a; i++) { if (a % i == 0) { res -= res / i; while (a % i == 0) a = a / i; } } if (a > 1) res -= res / a; return res; } int main() { int t; scanf("%d", &t); while (t--) { long long a, m; scanf("%lld %lld", &a, &m); long long k = gcd(a, m); long long ans = GetPhi(m / k); printf("%lld\n", ans); } return 0; } // gcd(a, m) = gcd(a + x, m) = k // gcd(a/k, m/k) = gcd(a/k + b, m/k) = 1 // phi[m/k];
E.Permutation Separation
令set1 <= val,set2 =val 为若在pos的位置把序列分成两半,则val:=val + 1的时候[1, pos - 1]加上val对应的cost,[pos, n - 1]就减去这个cost,这个可以用线段树维护
然后有一个坑,把我卡在test 6了很久很久,就是val是从0开始,不是从1开始
#include <cstdio> #include <algorithm> using namespace std; #define g(l, r) (l + r | l != r) #define o g(l, r) #define ls g(l, mid) #define rs g(mid + 1, r) const int N = 2 * 1e5 + 10; typedef long long ll; ll pos[N], p, w1, a[N]; ll pre[N], minn[N << 1], mark[N << 1]; int L, R; void build(int l, int r) { if (l == r) { minn[o] = pre[l]; return ; } int mid = l + r >> 1; build(l, mid); build(mid + 1, r); minn[o] = min(minn[ls], minn[rs]); } inline void PushDown(int l, int r) { if (mark[o] != 0) { int mid = l + r >> 1; mark[ls] += mark[o]; mark[rs] += mark[o]; minn[ls] = minn[ls] + mark[o]; minn[rs] = minn[rs] + mark[o]; mark[o] = 0; } } void update(int l, int r, int val) { if (L > R) return ; if (L <= l && R >= r) { minn[o] += val; mark[o] += val; return ; } PushDown(l, r); int mid = l + r >> 1; if (L <= mid) update(l, mid, val); if (R > mid) update(mid + 1, r, val); minn[o] = min(minn[ls], minn[rs]); } int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { int k; scanf("%d", &k); pos[k] = i; } for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); pre[i] = pre[i - 1] + a[i]; } build(1, n - 1); ll ans = minn[g(1, n - 1)]; for (int i = 1; i <= n; i++) { L = pos[i], R = n - 1; update(1, n - 1, -a[pos[i]]); L = 1, R = pos[i] - 1; update(1, n - 1, a[pos[i]]); ans = min(ans, minn[g(1, n - 1)]); } printf("%lld", ans); return 0; }
来源:https://www.cnblogs.com/cminus/p/12291878.html