用string时不要直接复制,会导致size和length变为0,建议使用push_back
操作就是枚举每一个字串,暴力查找,暴力删除,但与查找顺序有关
正着查找能拿30分,倒着查找能拿50分。比如说 ababaa
这个串,正着查删完会变成 baa
显然不对。这个串反过来又可以干灭倒着查找的方法,所以朴素的暴力不对。
统计原串中每个字母出现的次数,然后和暴力一样先枚举长度,长度一定是原串长的约数(优化×1)再用每个字母出现的次数除以长度得出可能的子串中各字母的个数(优化×2,不能整除,优化×3,跳过字母个数不满足要求的字串),然后用一个dp来确定这个字串是否合法。因为尽管子串(它组成了原串)可能被断成若干节,但夹在其中的每一段都是可以消掉的。
用表示原串的区间是否合法,如果为的倍数,就表示能否消掉。若有剩余,则剩余的一定需要是子串的前缀。
考虑第j个字符,分两种情况
#include <bits/stdc++.h>
#define For(i, l, r) for (int i = (l), i##end = (r); i <= i##end; ++i)
#define Fordown(i, r, l) for (int i = (r), i##end = (l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
const int maxn = 1001;
template <typename LDXIN>
LDXIN read() {
LDXIN 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;
}
using namespace std;
map<string, int> vis;
char a[maxn], sb[maxn];
int f[maxn][maxn], bukkit[26], bkt[26], cnt[26], sl, len;
int chk(int llen) {
for (int i = 1; i <= sl; i++) f[i][i] = (sb[1] == a[i]);
for (int len = 2; len <= sl; len++) {
char c = sb[(len - 1) % llen + 1];
for (int l = 1; l <= sl - len + 1; l++) {
int r = l + len - 1;
f[l][r] = f[l][r - 1] & (a[r] == c);
for (int k = 1; k * llen <= len && !f[l][r]; k++)
f[l][r] |= (f[l][r - k * llen] & f[r - k * llen + 1][r]);
}
}
return f[1][sl];
}
string ans;
int main() {
freopen("string.in", "r", stdin);
int T;
T = read<int>();
while (T--) {
scanf("%s", a + 1);
Set(bkt, 0);
vis.clear();
sl = strlen(a + 1);
For(i, 1, sl) bkt[a[i] - 'a']++;
for (len = 1; len <= sl; len++) {
if (sl % len) continue;
memcpy(bukkit, bkt, sizeof(bkt));
int num = sl / len, ok = 1;
For(i, 0, 25) {
if (bukkit[i] % num) {
ok = 0;
break;
}
}
if (!ok) continue;
For(i, 0, 25) bukkit[i] /= num;
bool getAns = 0;
for (int i = 1; i <= sl - len + 1; i++) {
memcpy(cnt, bukkit, sizeof(bukkit));
ok = 1;
Set(sb, 0);
for (int k = 0; k < len; k++) {
sb[k + 1] = a[i + k];
if (cnt[sb[k + 1] - 'a'] - 1 < 0) {
ok = 0;
break;
} else {
cnt[sb[k + 1] - 'a']--;
}
}
if (!ok) continue;
string cur = (string)(sb + 1);
if (vis[cur]) continue;
vis[cur];
if (chk(len)) {
if (!getAns) {
ans = cur;
getAns = 1;
} else {
if (cur < ans) {
ans = cur;
}
}
}
}
if (getAns) break;
}
cout << ans << endl;
}
}
这道题是个最短路……
考场上码了164行,把没学会的尽量往前放,把学会了的尽量往后放,喜提10分高分。为什么错?
因为一定是越早学会越好(就能越早教给后面的人),按我考场上的操作来的话可能有的人原本能学会却没有时间学会(例子,小A的区间是[5, 7],小B的区间是[4, 6],让小A在第7天恰饭导致原本能学会的小B无法学会)
#include <bits/stdc++.h>
#define For(i, l, r) for (int i = (l), i##end = (r); i <= i##end; ++i)
#define Fordown(i, r, l) for (int i = (r), i##end = (l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
const int maxn = 10010;
template <typename LDXIN>
LDXIN read() {
LDXIN 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;
}
struct INFO {
int with, l, r, id;
};
vector<INFO> p[maxn];
vector<int> unknown;
bool used[maxn];
int known[maxn], occu[maxn];
int type[maxn], ans[maxn];
int n, m, nowday;
int main() {
freopen("lunch.in", "r", stdin);
freopen("lunch.out", "w", stdout);
n = read<int>();
m = read<int>();
For(i, 1, m) {
int a, b, x, y;
a = read<int>();
b = read<int>();
x = read<int>();
y = read<int>();
p[a].push_back((INFO){b, x, y, i});
p[b].push_back((INFO){a, x, y, i});
}
For(i, 1, n) {
type[i] = read<int>();
if (type[i] == 1) {
if (known[i] < 0) {
cout << "Impossible" << endl;
return 0;
}
known[i] = 1;
bool fnd = 0;
for (auto fk : p[i]) {
if (!used[fk.id]) {
known[fk.with] = 1;
Fordown(d, fk.r, fk.l) {
if (occu[d] == 0 || occu[d] == 1) {
occu[d] = 1;
ans[fk.id] = d;
fnd = 1;
break;
}
}
if (!fnd) {
cout << "Impossible" << endl;
}
used[fk.id] = 1;
}
}
} else {
if (type[i] == -1) {
if (known[i] > 0) {
cout << "Impossible" << endl;
return 0;
}
known[i] = -1;
for (auto fk : p[i]) {
if (!used[fk.id]) {
known[fk.with] = -1;
bool fnd = 0;
For(d, fk.l, fk.r) {
if (occu[d] == 0 || occu[d] == -1) {
occu[d] = -1;
fnd = 1;
ans[fk.id] = d;
break;
}
}
if (!fnd) {
cout << "Impossible" << endl;
return 0;
}
used[fk.id] = 1;
}
}
} else {
if (known[i] == 0) unknown.push_back(i);
}
}
}
for (auto i : unknown) {
cout << "UKN: " << i << endl;
bool ha = 0;
for (auto fk : p[i]) {
if (!used[fk.id]) {
if (known[fk.with] != 0) {
known[i] = known[fk.with];
For(d, fk.l, fk.r) {
if (occu[d] == known[i] || occu[d] == 0) {
occu[d] = known[i];
ans[fk.id] = d;
}
}
ha = 1;
break;
}
}
}
if (!ha) {
int nt = 3;
for (auto fk : p[i]) {
if (!used[fk.id]) {
int type = 0;
For(d, fk.l, fk.r) {
if (occu[d] == 0 || type == 3) {
type = 3;
break;
}
if (occu[d] == -1) {
type |= 1;
}
if (occu[d] == 1) {
type |= 2;
}
}
if (type & nt == 0) {
cout << "Impossible" << endl;
return 0;
} else {
nt = nt & type;
}
}
if (nt == 1)
known[i] = -1;
else
known[i] = 1;
for (auto fk : p[i]) {
For(d, fk.l, fk.r) {
if (occu[d] == 0 || occu[d] == known[i]) {
known[fk.with] = known[i];
ans[fk.id] = d;
}
}
}
}
}
cout << known[3] << ' ' << known[4] << endl;
}
For(i, 1, m) { cout << ans[i] << endl; }
return 0;
}
如何保证可行性?
开一个数组表示某个人最早在什么时间能学会,对于一条边而言(起点from,终点to),如果,则表明在当前区间内这个人还没学会,所以只能是。如果那么吃饭的时间可以安排在,不限制让教。所以把所有不会的人的初值都赋为0x3f,然后跑最长路。
再开一个数组表示一个点何时可以学会,点1的值为0。接着跑最短路,每个点在之间取,并保证最大值小于
#include <bits/stdc++.h>
#define For(i, l, r) for (int i = (l), i##end = (r); i <= i##end; ++i)
#define Fordown(i, r, l) for (int i = (r), i##end = (l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
const int maxn = 201001;
template <typename LDXIN>
LDXIN read() {
LDXIN 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;
}
struct EDGE {
int to, nxt, l, r, from;
} edge[maxn * 2];
int head[maxn], tote;
void addEdge(int from, int to, int l, int r) {
edge[++tote].to = to;
edge[tote].from = from;
edge[tote].nxt = head[from];
edge[tote].l = l;
edge[tote].r = r;
head[from] = tote;
}
int n, m;
int known[maxn], low[maxn], tme[maxn];
struct knode {
int id, dis;
bool operator<(knode k) const { return dis > k.dis; }
};
struct uknode {
int id, dis;
bool operator<(uknode k) const { return dis < k.dis; }
};
priority_queue<knode> kq;
priority_queue<uknode> ukq;
int u[maxn], v[maxn], l[maxn], r[maxn];
int main() {
freopen("lunch.in", "r", stdin);
freopen("lunch.out", "w", stdout);
n = read<int>();
m = read<int>();
For(i, 1, m) {
u[i] = read<int>();
v[i] = read<int>();
l[i] = read<int>();
r[i] = read<int>();
addEdge(u[i], v[i], l[i], r[i]);
addEdge(v[i], u[i], l[i], r[i]);
}
For(i, 1, n) { known[i] = read<int>(); }
For(i, 1, n) {
if (known[i] == -1) {
low[i] = 0x3f3f3f3f;
ukq.push((uknode){i, low[i]});
}
}
// LP
while (!ukq.empty()) {
auto fnt = ukq.top();
ukq.pop();
int id = fnt.id;
int dis = fnt.dis;
for (int i = head[id]; i; i = edge[i].nxt) {
int to = edge[i].to;
if (dis > edge[i].r && edge[i].l + 1 > low[to]) {
low[to] = edge[i].l + 1;
ukq.push((uknode){to, low[to]});
}
}
}
if (low[1]) {
puts("Impossible");
return 0;
}
Set(tme, 0x3f);
tme[1] = 0;
kq.push((knode){1, 0});
// SP
while (!kq.empty()) {
auto fnt = kq.top();
kq.pop();
int id = fnt.id;
int dis = fnt.dis;
for (int i = head[id]; i; i = edge[i].nxt) {
int to = edge[i].to;
int mx = max(edge[i].l, max(dis, low[to]));
if (mx < tme[to] && mx <= edge[i].r)
tme[to] = mx, kq.push(knode{to, tme[to]});
}
}
For(i, 1, n) {
if (known[i] == 1 && tme[i] == 0x3f3f3f3f) {
puts("Impossible");
return 0;
}
}
for (int i = head[1]; i; i = edge[i].nxt) {
int to = edge[i].to;
if (known[to] == -1) {
puts("Impossible");
return 0;
}
}
For(i, 1, m) {
int ans = (max(tme[u[i]], tme[v[i]]) > r[i])
? l[i]
: max(l[i], max(tme[u[i]], tme[v[i]]));
printf("%d\n", ans);
}
return 0;
}
设表示前续遍历编号为的点能构成的子树种类数,直接枚举再枚举, ,如果满足要求则
要求:
的任何一个点中序遍历都不能在 以后
的任何一个点中序遍历都不能在以后
的中序遍历都不能在以后
然后算个2维前缀和,如果非0就不满足要求
For(i, 1, m) {
q[i].u = read<int>();
q[i].v = read<int>();
hv[q[i].u][q[i].v] = 1;
}
For(i, 1, n) {
For(j, 1, n) {
mat[i][j] =
hv[i][j] + mat[i - 1][j] + mat[i][j - 1] - mat[i - 1][j - 1];
}
}
For(i, 1, n) { dp[i][i] = 1; }
For(sz, 1, n) {
for (int i = 1; i + sz <= n; i++) {
int j = i + sz;
if (!getSum(i, i + 1, i, j)) dp[i][j] += dp[i + 1][j];
if (!getSum(i + 1, i, j, i)) dp[i][j] += dp[i + 1][j];
For(k, i, j) {
if (!getSum(k + 1, i + 1, j, k) && !getSum(k + 1, i, j, i) &&
!getSum(i, i + 1, i, k)) {
dp[i][j] += dp[i + 1][k] * dp[k + 1][j];
}
dp[i][j] %= mod;
}
}
}