过了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