@ljt12138
2017-04-13T23:43:36.000000Z
字数 18066
阅读 818
仍然缩点。缩完点之后每个半联通子图就相当于一条带权链(权值是一个scc的点数)。之后dp即可。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005, MAXM = 2000005;
struct g {
struct node {
int to, next;
} edge[MAXM];
int head[MAXN], top;
g(){ top = 0, memset(head, 0, sizeof head); }
void push(int i, int j)
{ edge[++top] = (node) {j, head[i]}, head[i] = top; }
}g, g1;
int dfn[MAXN], low[MAXN], stk[MAXN], top = 0, dft = 0;
int gp[MAXN], gtop = 0, gsiz[MAXN], vis[MAXN], n, m;
void tarjan(int nd)
{
dfn[nd] = low[nd] = ++dft;
stk[++top] = nd, vis[nd] = 1;
for (int i = g.head[nd]; i; i = g.edge[i].next) {
int to = g.edge[i].to;
if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);
else if (vis[to]) low[nd] = min(low[nd], dfn[to]);
}
if (dfn[nd] == low[nd]) {
int now; ++gtop;
do {
now = stk[top--], vis[now] = 0, gp[now] = gtop, gsiz[gtop]++;
} while (now != nd);
}
}
long long x;
set<pair<int,int> > hst;
int dp[MAXN], cnt[MAXN];
int dfs(int nd)
{
if (dp[nd] != -1) return dp[nd];
dp[nd] = gsiz[nd];
for (int i = g1.head[nd]; i; i = g1.edge[i].next)
dp[nd] = max(dp[nd], dfs(g1.edge[i].to)+gsiz[nd]);
return dp[nd];
}
int dfs_cnt(int nd)
{
if (cnt[nd] != -1) return cnt[nd];
if (!g1.head[nd]) return 1%x;
cnt[nd] = 0;
for (int i = g1.head[nd]; i; i = g1.edge[i].next) {
int to = g1.edge[i].to;
if (dp[nd] == dp[to] + gsiz[nd]) (cnt[nd] += dfs_cnt(to)) %= x;
}
return cnt[nd];
}
void work()
{
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; i++)
for (int j = g.head[i]; j; j = g.edge[j].next) {
int to = g.edge[j].to;
if (gp[i] != gp[to] && !hst.count(make_pair(gp[i], gp[to]))) {
hst.insert(make_pair(gp[i], gp[to]));
g1.push(gp[to], gp[i]); // G^R
}
}
memset(dp, -1, sizeof dp), memset(cnt, -1, sizeof cnt);
int ans1; long long ans2; ans1 = ans2 = 0;
for (int i = 1; i <= gtop; i++)
ans1 = max(ans1, dfs(i));
for (int i = 1; i <= gtop; i++)
if (dfs(i) == ans1)
(ans2 += dfs_cnt(i)) %= x;
printf("%d\n%lld\n", ans1, ans2);
}
int main()
{
scanf("%d%d%lld", &n, &m, &x);
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d%d", &u, &v), g.push(u, v);
}
work();
return 0;
}
缩点后暴力可过..
但是貌似有更好的算法??比如在拓扑图上随意dfs一棵生成树然后dfs序维护??
尚不清楚复杂度是否更优。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2005, MAXM = MAXN*MAXN;
struct graph {
struct node {
int to, next;
} edge[MAXM];
int head[MAXN], top;
graph(){top = 0, memset(head, 0, sizeof head); }
void push(int i, int j)
{ ++top, edge[top] = (node) {j, head[i]}, head[i] = top; }
} g, g1;
int dfn[MAXN], dft = 0, low[MAXN], vis[MAXN];
int stk[MAXN], top = 0;
int gp[MAXN], gtop = 0, gsiz[MAXN], n;
void tarjan(int nd)
{
vis[nd] = 1, dfn[nd] = low[nd] = ++dft, stk[++top] = nd;
for (int i = g.head[nd]; i; i = g.edge[i].next) {
int to = g.edge[i].to;
if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);
else if (vis[to]) low[nd] = min(low[nd], dfn[to]);
}
if (dfn[nd] == low[nd]) {
int now; ++gtop; //printf(" -- Group %d --\n", gtop);
do {
now = stk[top--];
gp[now] = gtop, gsiz[gtop]++, vis[now] = 0;
// cerr << now << " ";
} while(now != nd); //puts("");
}
}
int bfstime = 0;
queue<int> que;
int lkt[MAXN][MAXN];
void work()
{
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; i++)
for (int j = g.head[i]; j; j = g.edge[j].next) {
int to = g.edge[j].to;
if (gp[to] != gp[i] && !lkt[gp[i]][gp[to]]) {
lkt[gp[i]][gp[to]] = 1;
g1.push(gp[i], gp[to]);
}
}
int ans = 0;
memset(vis, 0, sizeof vis);
for (int i = 1; i <= gtop; i++) {
++bfstime;
que.push(i), vis[i] = bfstime;
int cnt = 0;
while (!que.empty()) {
int t = que.front(); que.pop(), cnt += gsiz[t];
for (int i = g1.head[t]; i; i = g1.edge[i].next) {
int to = g1.edge[i].to;
if (vis[to] != bfstime)
vis[to] = bfstime, que.push(to);
}
}
ans += cnt*gsiz[i];
}
cout << ans << endl;
}
char str[2005];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%s", str+1);
for (int j = 1; j <= n; j++)
if (str[j] == '1')
g.push(i, j);
}
work();
return 0;
}
今天来一波字符串。
这个题就比较神了。首先建出AC自动机,然后先求出每个节点的“顺着路过的总数
第一次做反了...
形如
sher
shers
her
的数据可以hack。因为shers不会算入her中去。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3000005;
int chl[MAXN][26], fail[MAXN], fin[MAXN], top = 0, root = 0;
vector<int> ids[MAXN];
int new_node()
{ return ++top, fail[top] = fin[top] = 0, memset(chl[top],0, sizeof chl[top]), top; }
void push(int &nd, const char *str, int id)
{
if (nd == 0) nd = new_node();
if (*str == '\0') fin[nd]++, ids[nd].push_back(id);
else push(chl[nd][*str-'a'], str+1, id);
}
struct node {
int to, next;
} edge[MAXN];
int head[MAXN], tp_edge = 0;
void push(int i, int j)
{ ++tp_edge, edge[tp_edge] = (node) {j, head[i]}, head[i] = tp_edge; }
int siz[MAXN], n;
queue<int> que;
void init()
{
que.push(root); fail[root] = 0;
while (!que.empty()) {
int t = que.front(); que.pop();
for (int i = 0; i < 26; i++) if (chl[t][i]) {
int p = fail[t];
while (p && !chl[p][i]) p = fail[p];
if (!p) fail[chl[t][i]] = root;
else fail[chl[t][i]] = chl[p][i];
que.push(chl[t][i]);
push(fail[chl[t][i]], chl[t][i]);
}
}
}
long long res[MAXN];
long long dp[MAXN];
int dfs(int nd)
{
if (siz[nd] != -1) return siz[nd];
siz[nd] = dp[nd];
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
siz[nd] += dfs(to);
}
return siz[nd];
}
long long dfs2(int nd)
{
if (dp[nd] != -1) return dp[nd];
dp[nd] = fin[nd];
for (int i = 0; i < 26; i++)
if (chl[nd][i])
dp[nd] += dfs2(chl[nd][i]);
return dp[nd];
}
char str[MAXN];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%s", str);
push(root, str, i);
}
init();
memset(siz, -1, sizeof siz);
memset(dp, -1, sizeof dp);
dfs2(root);
dfs(root);
for (int i = 1; i <= top; i++)
for (int j = 0; j < fin[i]; j++)
res[ids[i][j]] = siz[i];
for (int i = 1; i <= n; i++)
printf("%lld\n", res[i]);
return 0;
}
首先
区间dp是正解,方程容易想到,唯一的字符串trick就是用hashk判断相等。
特别注意取某一区间hash的小技巧。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
char str[MAXN];
int n;
unsigned long long hash_tab[MAXN], pwr[MAXN];
unsigned long long hash_val(int i, int j)
{ return hash_tab[j]-hash_tab[i-1]*pwr[j-i+1]; }
int dp[MAXN][MAXN];
int len(int num)
{ return num <= 9 ? 1 : (num <= 99 ? 2 : 3); }
int dfs(int i, int j)
{
if (dp[i][j] != -1) return dp[i][j];
if (i == j) return 1;
dp[i][j] = INT_MAX;
for (int k = i; k < j; k++)
dp[i][j] = min(dp[i][j], dfs(i,k)+dfs(k+1,j));
for (int k = 1; k <= j-i+1; k++) { // 枚举每一块长度
if ((j-i+1)%k != 0) continue;
int flag = 1; unsigned long long val = 0;
for (int p = 0; p < (j-i+1)/k; p++) {
if (p == 0) val = hash_val(i+p*k, i+(p+1)*k-1);
else if (val != hash_val(i+p*k, i+(p+1)*k-1)) { flag = 0; break; }
}
if (flag) dp[i][j] = min(dp[i][j], dfs(i, i+k-1)+2+len((j-i+1)/k));
}
return dp[i][j];
}
int main()
{
scanf("%s", str+1), n = strlen(str+1);
pwr[0] = 1;
for (int i = 1; i <= n; i++) pwr[i] = pwr[i-1]*31;
for (int i = 1; i <= n; i++) hash_tab[i] = hash_tab[i-1]*31+(str[i]-'A'+1);
memset(dp, -1, sizeof dp);
cout << dfs(1, n) << endl;
return 0;
}
乍一看和字符串毫无关系...
事实上,存在一个等差数列当且仅当存在三个点
然后对于这种对称的处理思路就两种:
FFT貌似不太好处理,但回文串很兹瓷啊。用线段树记录每个点是否存在1/2并维护区间哈希,然后正反算哈希判断是不是相等即可。如果在某一时刻
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
unsigned long long hash_tab[MAXN*4], hash_rev[MAXN*4], power[MAXN];
int lc[MAXN*4], rc[MAXN*4], l[MAXN*4], r[MAXN*4], top = 0, root = 0;
int n, a[MAXN];
inline int siz(int nd) { return r[nd]-l[nd]+1; }
void build(int &nd, int opl, int opr)
{
nd = ++top, hash_tab[nd] = hash_rev[nd] = 1, lc[nd] = rc[nd] = 0, l[nd] = opl, r[nd] = opr;
if (opl < opr) {
build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]];
hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]];
}
}
void modify(int nd, int pos)
{
if (l[nd] == r[nd]) hash_tab[nd] = hash_rev[nd] = 2;
else {
modify(pos<=(l[nd]+r[nd])/2?lc[nd]:rc[nd], pos);
hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]];
hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]];
}
}
unsigned long long query(int nd, int opl, int opr)
{
if (l[nd] == opl && r[nd] == opr) return hash_tab[nd];
else {
int mid = (l[nd]+r[nd])/2;
if (opr <= mid) return query(lc[nd], opl, opr);
else if (opl > mid) return query(rc[nd], opl, opr);
else return query(lc[nd], opl, mid)+power[mid-opl+1]*query(rc[nd], mid+1, opr);
}
}
unsigned long long query_reversed(int nd, int opl, int opr)
{
if (l[nd] == opl && r[nd] == opr) return hash_rev[nd];
else {
int mid = (l[nd]+r[nd])/2;
if (opr <= mid) return query_reversed(lc[nd], opl, opr);
else if (opl > mid) return query_reversed(rc[nd], opl, opr);
else return power[opr-mid]*query_reversed(lc[nd], opl, mid)+query_reversed(rc[nd], mid+1, opr);
}
}
void init()
{
scanf("%d", &n);
top = root = 0;
build(root, 1, n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
}
int main()
{
int T; scanf("%d", &T);
power[0] = 1;
for (int i = 1; i <= 10000; i++) power[i] = power[i-1]*31;
while (T--) {
init();
int flag = 0;
for (int i = 1; i <= n; i++) {
// cerr << query(root, 1, 3) << "--" << query_reversed(root, 1, 3) << endl;
if (a[i] <= n-a[i]+1) {
if (i >= 2 && i < n && query(root, 1, 2*a[i]-1) != query_reversed(root, 1, 2*a[i]-1)) {
flag = 1; break;
}
} else {
int k = 2*(n-a[i]+1)-1;
if (i >= 2 && i < n && query(root, n-k+1, n) != query_reversed(root, n-k+1, n)) {
flag = 1; break;
}
}
modify(root, a[i]);
}
if (flag) puts("Y");
else puts("N");
}
return 0;
}
首先
注意:hash一定要用ull...
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 400005, lgn = 20;
int n, m, k, bas, sqr;
unsigned long long hash_val(int a[], int l, int r)
{
unsigned long long ans = 0;
for (int i = l; i <= r; i++)
ans = ans*bas+a[i];
return ans;
}
struct query {
int l, r, dat, id, ans;
friend bool operator < (const query &a, const query &b)
{ return a.l/sqr != b.l/sqr ? a.l < b.l : a.r < b.r; }
} q[MAXN];
bool cmp(const query &a, const query &b)
{ return a.id < b.id; }
int a[MAXN], tmp[30];
unsigned long long d[MAXN], dx[MAXN], qu[MAXN], top = 0;
void dx_init()
{
memcpy(dx, d, sizeof d);
sort(dx+1, dx+top+1);
}
int dx_num(unsigned long long dat)
{ return lower_bound(dx+1, dx+top+1, dat)-dx; }
int tab[MAXN];
int main()
{
scanf("%d%d%d", &n, &m, &k), bas = n+1;
sqr = sqrt(n); // 分块大小
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i+k-1 <= n; i++) d[++top] = hash_val(a, i, i+k-1);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &q[i].l, &q[i].r); q[i].r = q[i].r-k+1;
for (int j = 1; j <= k; j++) scanf("%d", &tmp[j]);
qu[i] = hash_val(tmp, 1, k);
d[++top] = qu[i], q[i].id = i;
}
dx_init(); // 离散化
for (int i = 1; i+k-1 <= n; i++) a[i] = dx_num(d[i]);
for (int i = 1; i <= m; i++) q[i].dat = dx_num(qu[i]);
sort(q+1, q+m+1);
memset(tab, 0, sizeof tab);
int L = q[1].l, R = q[1].r;
for (int i = L; i <= R; i++) tab[a[i]]++; q[1].ans = tab[q[1].dat];
for (int i = 2; i <= m; i++) {
if (q[i].l > q[i].r) continue;
while (L < q[i].l) tab[a[L++]]--;
while (L > q[i].l) tab[a[--L]]++;
while (R < q[i].r) tab[a[++R]]++;
while (R > q[i].r) tab[a[R--]]--;
q[i].ans = tab[q[i].dat];
}
sort(q+1, q+m+1, cmp);
for (int i = 1; i <= m; i++)
if (q[i].ans) puts("No");
else puts("Yes");
return 0;
}
看题解dfs序+树状数组就水过去了,
但是写了链剖
然而
玄学啊...当然也可能我写跪了...
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 250005;
int C[MAXN], n, dstop = 0;
int lowbit(int i) { return i&(-i); }
void modify(int pos, int dt)
{ for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }
int sum(int pos)
{
int ans = 0;
for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];}
return ans;
}
int sum(int l, int r)
{ return sum(r)-sum(l-1); }
struct node {
int to, next;
} edge[MAXN*2];
int head[MAXN], top;
void push(int i, int j)
{ ++top, edge[top] = (node){j, head[i]}, head[i] = top; }
int siz[MAXN], id[MAXN], ind[MAXN], fa[MAXN];
void dfs1(int nd)
{
siz[nd] = 1;
for (int i = head[nd]; i; i = edge[i].next)
dfs1(edge[i].to), siz[nd] += siz[edge[i].to], fa[edge[i].to] = nd;
}
void dfs2(int nd, int from = 0)
{
id[nd] = ++dstop, ind[nd] = from, modify(id[nd], 1);
int hev = 0;
for (int i = head[nd]; i; i = edge[i].next)
if (siz[edge[i].to] > siz[hev])
hev = edge[i].to;
if (!hev) return;
dfs2(hev, from);
for (int i = head[nd]; i; i = edge[i].next)
if (edge[i].to != hev)
dfs2(edge[i].to, edge[i].to);
}
void change(int nd)
{ modify(id[nd], -1); }
int ask(int nd)
{
int ans = 0;
while (nd) {
// cout << nd << endl;
ans += sum(id[ind[nd]], id[nd]), nd = fa[ind[nd]];
}
return ans;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
if (u > v) swap(u,v);
push(u, v);
}
dfs1(1), dfs2(1);
int m; scanf("%d", &m);
for (int i = 1; i <= m+n-1; i++) {
char s; int u, v;
scanf("\n%c", &s);
if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); }
else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)-1); }
else throw;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 250005;
int chl[MAXN][2], dat[MAXN], hv[MAXN], stk[MAXN], stktop = 0, fa[MAXN];
int rev[MAXN], n, m;
bool is_rt(int nd)
{ return nd != chl[fa[nd]][0] && nd != chl[fa[nd]][1]; }
void update(int nd)
{ dat[nd] = dat[chl[nd][0]] + dat[chl[nd][1]] + hv[nd];}
void pdw(int nd)
{
if (!rev[nd]) return;
int &lc = chl[nd][0], &rc = chl[nd][1]; rev[nd] = 0;
if (lc) rev[lc] ^= 1;
if (rc) rev[rc] ^= 1;
swap(lc, rc);
}
void zig(int nd)
{
int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
int son = chl[nd][tp^1];
if (!is_rt(p)) chl[g][tg] = nd; chl[nd][tp^1] = p, chl[p][tp] = son;
fa[son] = p, fa[p] = nd, fa[nd] = g;
update(p), update(nd);
}
void splay(int nd)
{
stk[stktop = 1] = nd;
for (int i = nd; !is_rt(i); i = fa[i]) stk[++stktop] = fa[i];
while (stktop) pdw(stk[stktop--]);
while (!is_rt(nd)) {
int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
if (is_rt(p)) { zig(nd); break; }
else if (tp == tg) zig(p), zig(nd);
else zig(nd), zig(nd);
}
}
void access(int x)
{
for (int y = 0; x; x = fa[y = x])
splay(x), chl[x][1] = y, update(x);
}
void make_rt(int x)
{ access(x), splay(x), rev[x] ^= 1; }
void link(int i, int j)
{ make_rt(j), fa[j] = i, access(j); }
void change(int nd)
{ make_rt(nd), splay(nd), hv[nd]--, update(nd); }
int ask(int nd)
{ make_rt(1), access(nd), splay(nd); return hv[nd]+dat[chl[nd][0]]; }
int main()
{
scanf("%d", &n);
for (int i = 2; i <= n; i++) hv[i] = 1;
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
if (u > v) swap(u, v);
link(u, v);
}
scanf("%d", &m);
for (int i = 1; i <= n+m-1; i++) {
char c; int u, v;
scanf("\n%c", &c);
if (c == 'W') { scanf("%d", &u), printf("%d\n", ask(u)); }
else if (c == 'A') { scanf("%d%d", &u, &v), change(max(u, v)); }
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 250005;
int C[MAXN], n, dstop = 0;
int lowbit(int i) { return i&(-i); }
void modify(int pos, int dt)
{ for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }
int sum(int pos)
{
int ans = 0;
for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];}
return ans;
}
struct node {
int to, next;
} edge[MAXN];
int head[MAXN], top = 0;
void push(int i, int j)
{ ++top, edge[top] = (node){j, head[i]}, head[i] = top; }
int depth[MAXN], dfi[MAXN], dfo[MAXN], dft = 0;
void dfs(int nd)
{
dfi[nd] = ++dft;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
depth[to] = depth[nd]+1;
dfs(to);
}
dfo[nd] = dft;
}
void change(int nd)
{ modify(dfi[nd], 1), modify(dfo[nd]+1, -1); }
int ask(int nd)
{ return depth[nd]-sum(dfi[nd]); }
int main()
{
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
if (u > v) swap(u,v);
push(u, v);
}
depth[1] = 0, dfs(1);
int m; scanf("%d", &m);
for (int i = 1; i <= n+m-1; i++) {
char s; int u, v;
scanf("\n%c", &s);
if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); }
else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)); }
else throw;
}
return 0;
}
就是splay维护最小值和最小值位置,加上反转操作即可。
然而debug能力是硬伤...
注意重复元素的处理,就是
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int chl[MAXN][2], fa[MAXN], rev[MAXN], stk[MAXN], stktop = 0;
int top = 0, min_pos[MAXN], siz[MAXN], root = 0;
long long min_val[MAXN], dat[MAXN];
void update(int nd)
{
min_val[nd] = min(dat[nd], min(min_val[chl[nd][0]], min_val[chl[nd][1]]));
min_pos[nd] = min_val[nd] == min_val[chl[nd][0]] ? min_pos[chl[nd][0]] : (min_val[nd] == dat[nd] ? nd : min_pos[chl[nd][1]]);
siz[nd] = siz[chl[nd][0]] + siz[chl[nd][1]] + 1;
}
inline int new_node(long long d) { return ++top, dat[top] = d, update(top), top;}
void pdw(int nd)
{
if (!rev[nd]) return;
int &lc = chl[nd][0], &rc = chl[nd][1];
if (lc) rev[lc] ^= 1;
if (rc) rev[rc] ^= 1;
swap(lc, rc), rev[nd] ^= 1;
}
void zig(int nd)
{
int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
int son = chl[nd][tp^1];
fa[son] = son==0?0:p, fa[p] = nd, fa[nd] = g;
chl[g][tg] = g==0?0:nd, chl[nd][tp^1] = p, chl[p][tp] = son;
root = g?root:nd;
update(p), update(nd);
}
void splay(int nd, int tar = 0)
{
stk[stktop = 1] = nd;
for (int i = nd; fa[i]; i = fa[i]) stk[++stktop] = fa[i];
for (; stktop; stktop--) pdw(stk[stktop]);
while (fa[nd] != tar) {
int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
if (g == tar) {zig(nd); break; }
else if (tp == tg) zig(p), zig(nd);
else zig(nd), zig(nd);
}
}
void dfs(int nd)
{
if (!nd) return;
pdw(nd);
dfs(chl[nd][0]);
cerr << dat[nd] << " ";
dfs(chl[nd][1]);
}
void insert(long long nd)
{
if (root == 0) root = new_node(nd);
else {
chl[root][1] = new_node(nd), fa[top] = root;
splay(top), update(top);
// dfs(top);
}
}
int get_min()
{
splay(min_pos[root]);
int ans = siz[chl[root][0]]+1;
return ans;
}
int get_by_order(int k)
{
int nd = root; k--; // have k element on left
while (nd) {
pdw(nd), update(nd);
if (siz[chl[nd][0]] == k) break;
nd = siz[chl[nd][0]]>k?chl[nd][0]:(k -= siz[chl[nd][0]]+1, chl[nd][1]);
}
return nd;
}
int get_segment(int l, int r)
{
if (l == 1 && r == siz[root]) return root;
if (l == 1) return splay(get_by_order(r+1)), chl[root][0];
if (r == siz[root]) return splay(get_by_order(l-1)), chl[root][1];
return splay(get_by_order(l-1)), splay(get_by_order(r+1), root), chl[chl[root][1]][0];
}
void del_root()
{
int t = get_segment(siz[chl[root][0]]+1, siz[chl[root][0]]+1);
int tp = chl[fa[t]][0] != t; chl[fa[t]][tp] = 0;
for (int i = fa[t]; i; i = fa[i]) update(i);
fa[t] = 0;
}
void reverse(int l, int r)
{
int t = get_segment(l, r);
rev[t] ^= 1;
}
int ans()
{
int ret = get_min();
reverse(1, ret);
splay(min_pos[root]), del_root();
return ret;
}
int n;
int main()
{
memset(min_val, 127/3, sizeof min_val);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int u; scanf("%d", &u); insert((long long)u*(n+1)+i);
}
for (int i = 1; i <= n; i++) printf("%d ", ans()+i-1);
return 0;
}
大爷题解:http://blog.csdn.net/aarongzk/article/details/50472209#
就是AC自动机上dp,然而数位dp仍然跪烂...要注意前导零的处理。
AC自动机忘记push儿子调试1h...
#include <bits/stdc++.h>
using namespace std;
const int MAXL = 1505;
int vis[MAXL];
struct ACM {
struct node {
int chl[10];
int finished, fail;
node() { memset(chl, 0, sizeof chl), finished = fail = 0; }
} tree[MAXL];
int top, root;
ACM() { top = root = 0; }
inline int new_node() { return ++top; }
void insert(int &nd, const char *str)
{
if (!nd) nd = new_node();
if (*str == '\0') tree[nd].finished = 1, vis[nd] = 1;
else insert(tree[nd].chl[*str-'0'], str+1);
}
queue<int> que;
void init()
{
tree[root].fail = 0, que.push(root);
while (!que.empty()) {
int nd = que.front(); que.pop(); vis[nd] |= vis[tree[nd].fail];
for (int i = 0; i < 10; i++) {
if (!tree[nd].chl[i]) continue;
int p = tree[nd].fail;
while (p && !tree[p].chl[i]) p = tree[p].fail;
if (!p) tree[tree[nd].chl[i]].fail = root;
else tree[tree[nd].chl[i]].fail = tree[p].chl[i];
que.push(tree[nd].chl[i]);
}
} ;
}
int trans(int nd, int ths)
{
if (tree[nd].chl[ths]) return tree[nd].chl[ths];
int p = tree[nd].fail;
while (p && !tree[p].chl[ths]) p = tree[p].fail;
if (!p) return root;
else return tree[p].chl[ths];
}
} ac;
long long dp[1500][MAXL][3]; // 1 随意 0 不随意
char str[MAXL]; int s[MAXL];
long long mod = 1e9+7;
int n, m;
int main()
{
memset(vis, 0, sizeof vis);
scanf("%s", str+1); n = strlen(str+1);
for (int i = 1; i <= n; i++) s[i] = str[i]-'0';
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
scanf("%s", str);
ac.insert(ac.root, str);
}
long long ans = 0;
ac.init();
memset(dp, 0, sizeof dp);
for (int i = 1; i < 10; i++) if (!vis[ac.trans(ac.root, i)]) dp[2][ac.trans(ac.root, i)][0]++;
for (int i = 2; i < n; i++)
for (int j = 1; j <= ac.top; j++)
for (int k = 0; k < 10; k++) if (!vis[ac.trans(j, k)])
(dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod;
for (int i = 2; i <= n; i++)
for (int j = 1; j <= ac.top; j++)
(ans += dp[i][j][0]) %= mod; // 前导0
memset(dp, 0, sizeof dp);
for (int i = 1; i <= s[1]; i++)
if (!vis[ac.trans(ac.root, i)])
dp[2][ac.trans(ac.root, i)][i == s[1]]++;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= ac.top; j++)
for (int k = 0; k < 10; k++) {
if (vis[ac.trans(j, k)]) continue;
(dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod;
if (k < s[i]) (dp[i+1][ac.trans(j, k)][0] += dp[i][j][1]) %= mod;
else if (k == s[i]) (dp[i+1][ac.trans(j, k)][1] += dp[i][j][1]) %= mod;
}
}
for (int i = 1; i <= ac.top; i++)
(ans += dp[n+1][i][0]+dp[n+1][i][1]) %= mod;
cout << ans << endl;
return 0;
}