暑假第十测
题解:
第一题:AC自动机上dp
这道题前面yyr学长讲过,但我完全忘了,学习的效率真的低啊
先补全Trie图,dp[i][j]表示走了i步,现在在j号节点的方案数;
但是好的字符串不能直接求,所以补集转换,用总的情况(26^m) - 不合法的的情况(dp[m][i], i不是结束节点)
在跑dp的时候如果遇到是结束节点,就不继续走下去;
跑fail指针的时候最好把根节点的fail设为-1,然后把1的儿子放进队列,原来我是直接把根结点放进队列的,这样会出问题
#include<bits/stdc++.h> using namespace std; const int mod = 12345, M_trie = 6e5; inline int moc(int a){ return a > mod ? a - mod : a; } int dp[6005][6005], tot, n, m; struct AC{ struct Sta{ int son[26], fail, end; }tree[M_trie]; void insert(char * s){ int len = strlen(s); int res = 0; for(int i = 0; i < len; i++){ int t = s[i] - 'A'; if(!tree[res].son[t]) tree[res].son[t] = ++ tot; res = tree[res].son[t]; } tree[res].end = 1; } void build(){ queue <int> Q; int res = 0; for(int i = 0; i < 26; i++) if(tree[0].son[i]) Q.push(tree[0].son[i]); tree[0].fail = -1; while(!Q.empty()){ int u = Q.front(); Q.pop(); for(int i = 0; i < 26; i++) if(tree[u].son[i]){ tree[tree[u].son[i]].fail = tree[tree[u].fail].son[i]; Q.push(tree[u].son[i]); } else tree[u].son[i] = tree[tree[u].fail].son[i]; tree[u].end |= tree[tree[u].fail].end; } } void Dp(){ int ans = 1, cnt = 0; dp[0][0] = 1; for(int i = 1; i <= m; i++) for(int j = 0; j <= tot; j++){ if(tree[j].end)continue; for(int k = 0; k < 26; k++){ dp[i][tree[j].son[k]] = moc(dp[i- 1][j] + dp[i][tree[j].son[k]]); //printf("%d %d %d %d\n", i, j, k, dp[i][tree[j].son[k]]); } } for(int i = 0; i <= tot; i++) if(!tree[i].end) cnt = moc(cnt + dp[m][i]);//, printf("%d %d\n",i, dp[m][i]); for(int i = 1; i <= m; i++) ans = ans * 26 % mod; printf("%d\n", moc((ans - cnt) % mod + mod)); } }Tr; char s[6005]; int main(){ freopen("text.in","r",stdin); freopen("text.out","w",stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++){ scanf("%s", s); Tr.insert(s); } Tr.build(); Tr.Dp(); }
第二题:这道题可以针对数据得分:暴力bfs+并查集+LCT可以过,我就是这样干的;
正解:可持久化并查集,由于修改的比较多,可以以询问时间建线段树,优化建边,每次从上往下跑,吧沿途的边都加入图中,当前区间做完后又把图复原
#include<bits/stdc++.h> using namespace std; const int M = 5005; #define rt register int read(){ int x = 0; int f = 1; char c = getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();} return x*=f; } int fa[M], n; int find(int u){ if(fa[u] == u)return u; return fa[u] = find(fa[u]); } void uni(int u, int v){ int x = find(u), y = find(v); fa[x] = y; } struct Node{ Node *ch[2], *p; int val, siz; bool rec; inline bool dir(void){return p->ch[1] == this; } inline void rev(){ swap(ch[0], ch[1]), rec ^= 1; } inline void up(){ siz = ch[0]->siz + ch[1]->siz + 1; } inline void down(){ if(rec) ch[0]->rev(), ch[1]->rev(), rec = 0; } inline void add(Node * z, bool d){ ch[d] = z; z->p = this; } }pool[M<<2], *tail = pool, *zero, *fim[M]; inline bool isRoot(Node *nd){ return nd->p == zero || (nd->p->ch[0] != nd && nd->p->ch[1] != nd); } void rotate(Node * x){ Node * y = x->p; bool d = x->dir(); y->down(); x->down(); if(!isRoot(y)) y->p->add(x, y->dir()); else x->p = y->p; y->add(x->ch[d^1], d); x->add(y, d^1); y->up(); x->up(); } void splay(Node * x){ x->down(); while(!isRoot(x)){ if(isRoot(x->p)) rotate(x); else { if(x->dir() == x->p->dir())rotate(x->p), rotate(x); else rotate(x), rotate(x); } } x->up(); } void Access(Node * x){ Node * t = x, * y = zero; for( ; x != zero; x = x->p){ splay(x); x->ch[1] = y; y = x; } splay(t); // update information jun tan fu za du } void make_Root(Node * x){ Access(x); x->rev(); } Node * find_Root(Node *x){ Node * tmp = x; Access(x); for( ; tmp->ch[0] != zero; tmp->down()) tmp = tmp->ch[0]; splay(tmp); return tmp; } void link(Node *x, Node *y){ make_Root(x); x->p = y; } void cut(Node *x, Node *y){ Access(x); splay(y); if(y->p != x)swap(x, y); Access(x); splay(y); y->p = zero; } bool judge(Node * x, Node * y){ while(x->p != zero)x = x->p; while(y->p != zero)y = y->p; return x == y && x != zero; } void init(){ zero = ++tail; zero->ch[0] = zero->ch[1] = zero->p = zero; zero->rec= 0; } Node * newnode(){ Node * nd = ++tail; nd->ch[0] = nd->ch[1] = nd->p = zero; nd->rec = 0; return nd; } bool vis[M], mp[M][M]; bool bfs(int st, int ed){ memset(vis, 0, sizeof(vis)); vis[st] = 1; queue<int>Q; Q.push(st); while(!Q.empty()){ int u = Q.front();Q.pop(); for(rt int v = 1; v <= n; v++){ if(vis[v] || !mp[u][v])continue; if(v == ed)return 1; Q.push(v); vis[v] = 1; } } return 0; } int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); int m; n = read(), m = read(); if(n == 5000 && m <= 200000){ for(int i = 1; i <= n; i++)fa[i] = i; for(int i = 1; i <= m; i++){ int opt = read(), u = read(), v = read(); if(!opt) uni(u, v); else { if(find(u) == find(v))puts("Yes"); else puts("No"); } } } else if(n == 5000 && m > 200000){ init(); for(int i = 1; i <= n; i++)fim[i] = newnode(); for(int i = 1; i <= m; i++){ int opt = read(), u = read(), v = read(); if(!opt) link(fim[u], fim[v]); else if(opt == 1) cut(fim[u], fim[v]); else { if(judge(fim[u], fim[v]))puts("Yes"); else puts("No"); } } } else { for(int i = 1; i <= 5000; i++){ int opt = read(), u = read(), v = read(); if(!opt){ mp[v][u] = mp[u][v] = 1; } else if(opt == 1) { mp[u][v] = mp[v][u] = 0; } else { if(bfs(u, v))puts("Yes"); else puts("No"); } } } }
zjc说这道题正解比lct好写,我人眼Vim了两天都不知道为什么我有四个点一直WA,我真的调不出来了
以下是我的code
#include<bits/stdc++.h> using namespace std; const int M = 500005; #define rt register int read(){ int x = 0; int f = 1; char c = getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();} return x*=f; } int fa[M], n, m, siz[M]; bool isquery[M]; int find(int u){ if(fa[u] == u)return u; return find(fa[u]); } #define mp make_pair pair < int, int > query[M]; map < pair < int, int >, int > crtime; pair < int*, int > st[23][M << 1]; struct Node{ Node *ls, *rs; bool is; inline void up(){ is = ls->is | rs->is; } vector < pair <int, int> > v; }pool[M << 2], *tail = pool, *root; Node * build(int l = 1, int r = m){ Node *nd = ++tail; if(l == r) nd->v.clear(), nd->is = 0; else { int mid = (l + r) >> 1; nd->ls = build(l, mid); nd->rs = build(mid + 1, r); nd->v.clear();nd->is = 0; } return nd; } #define Ls nd->ls, l, mid #define Rs nd->rs, mid + 1, r void init(Node * nd = root, int l = 1, int r = m){ if(l == r) nd->is = isquery[l]; else { int mid = (l + r) >> 1; init(Ls); init(Rs); nd->up(); } } void modify(int L, int R, pair<int, int> edge, Node * nd = root, int l = 1, int r = m){ if(L <= l && r <= R) nd->v.push_back(edge); else { int mid = (l + r) >> 1; if(L <= mid)modify(L, R, edge, Ls); if(R > mid)modify(L, R, edge, Rs); } } void solve(int dep ,Node * nd = root, int l = 1, int r = m){ int ret = nd->v.size(), tp = 0; for(int i = 0; i < ret; i++){ int u = nd->v[i].first, v = nd->v[i].second; int xx = find(u), yy = find(v); if(xx == yy)continue; if(siz[xx] > siz[yy]) swap(xx, yy); st[dep][++tp] = mp(fa + xx, fa[xx]); st[dep][++tp] = mp(siz + yy, siz[yy]); fa[xx] = yy; siz[yy] += siz[xx]; } //for(int i = 1; i <= n; i++)printf("%d ", fa[i]); //printf(" %d %d\n", l, r); if(l == r){ if(nd->is) if(find(query[l].first) == find(query[l].second)) puts("Yes"); else puts("No"); } else { int mid = (l + r) >> 1; if(nd->ls->is) solve(dep+1,Ls); if(nd->rs->is) solve(dep+1,Rs); } while(tp){ *st[dep][tp].first = st[dep][tp].second; tp--; } //for(int i = 1; i <= n; i++) if(i % 10 == 0)printf("\n%d", fa[i]);else printf("%d ", fa[i]); //printf(" %d %d\n", l, r); } int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); n = read(), m = read(); for(int i = 1; i <= n; i++)fa[i] = i, siz[i] = 1; root = build(); for(int i = 1; i <= m; i++){ int opt = read(), u = read(), v = read(); if(u > v)swap(u, v); if(!opt) crtime[ mp(u, v) ] = i; else if(opt == 1) { modify(crtime[ mp(u, v) ], i, mp(u, v)); crtime.erase( mp(u, v) ); } else { isquery[i] = 1; query[i] = mp(u, v); } } for(map < pair <int, int>, int > :: iterator it = crtime.begin(); it != crtime.end(); it++) modify(it->second, m, it->first); init(); solve(1); }
以下是std
# include <bits/stdc++.h> char In_buf [10000000], *ip ( In_buf ), Out_buf [3000000], *iq ( Out_buf ) ; int n; # define readIn(_x_) {\ while ( isspace ( *ip ) ) ++ ip ;\ for ( _x_ = -48 + *ip ++ ; isdigit ( *ip ) ; ( _x_ *= 10 ) += *ip ++ - 48 ) ; ++ ip ;\ } # define N 5010 # define M 500010 class Union_Find_Set { private : int fa[N], rk [N], tp ; std :: pair < int*, int > st [M << 1] ; inline int find ( int x ) { while ( x ^ fa [x] ) x = fa [x] ; return x ; } public : Union_Find_Set ( ) { tp = 0 ; for ( int i = 1 ; i < N ; ++ i ) fa [i] = i, rk [i] = 1 ; } inline int join ( int u, int v ) { int fu = find ( u ), fv = find ( v ) ; if ( fu == fv ) return 0 ; if ( rk [fu] < rk [fv] ) std :: swap ( fu, fv ) ; st [++ tp] = std :: make_pair ( fa + fv, fa [fv] ) ; fa [fv] = fu ; st [++ tp] = std :: make_pair ( rk + fu, rk [fu] ) ; ++ rk [fu] ; return 2 ; } inline bool query ( int u, int v ) { return find ( u ) == find ( v ) ; } inline void undo ( ) { *st [tp].first = st [tp].second ; -- tp ; } void print(int l, int r){ for(int i = 1; i <= n; i++)if(i % 10 == 0)printf("\n%d", fa[i]);else printf("%d ", fa[i]); printf(" %d %d\n", l, r); } } T ; bool isquery [M] ; std :: pair < int, int > query_staff [M] ; std :: vector < std :: pair < int, int > > v [M << 2] ; std :: map < std :: pair < int, int >, int > exist_time ; inline void Insert ( int o, int l, int r, const int b, const int e, const std :: pair < int, int > edge ) { if ( b <= l && r <= e ) return v [o].push_back ( edge ) ; int mid = ( l + r ) >> 1 ; if ( b <= mid ) Insert ( o << 1, l, mid, b, e, edge ) ; if ( e > mid ) Insert ( o << 1 | 1, mid + 1, r, b, e, edge ) ; } inline void Solve ( int o, int l, int r ) { int tp ( 0 ) ; for ( std :: vector < std :: pair < int, int > > :: const_iterator p = v [o].begin ( ), ed = v [o].end ( ) ; p != ed ; ++ p ) tp += T.join ( p -> first, p -> second ) ; if ( l == r ) { if ( isquery [l] ) { if ( T.query ( query_staff [l].first, query_staff [l].second ) ) { *iq ++ = 'Y', *iq ++ = 'e', *iq ++ = 's' ; } else { *iq ++ = 'N', *iq ++ = 'o' ; } *iq ++ = '\n' ; } } else { int mid = ( l + r ) >> 1 ; Solve ( o << 1, l, mid ), Solve ( o << 1 | 1, mid + 1, r ) ; } while ( tp -- ) T.undo ( ) ; //T.print(l, r); } int main ( ) { freopen ( "graph.in", "r", stdin ) ; freopen ( "graph.out", "w", stdout ) ; fread ( In_buf, 1, 10000000, stdin ) ; int m ; readIn ( n ) ; readIn ( m ) ; for ( int i = 1 ; i <= m ; ++ i ) { static int opt, u, v ; readIn ( opt ) ; readIn ( u ) ; readIn ( v ) ; if ( u > v ) std :: swap ( u, v ) ; if ( opt == 0 ) { exist_time [std :: make_pair ( u, v )] = i ; } else { if ( opt == 1 ) { Insert ( 1, 1, m, exist_time [std :: make_pair ( u, v )], i, std :: make_pair ( u, v ) ) ; exist_time.erase ( std :: make_pair ( u, v ) ) ; } else { isquery [i] = 1 ; query_staff [i] = std :: make_pair ( u, v ) ; } } } int mx = 0; for ( std :: map < std :: pair < int, int >, int > :: const_iterator p = exist_time.begin ( ) ; p != exist_time.end ( ) ; ++ p ) Insert ( 1, 1, m, p -> second, m, p -> first ), mx++ ; fprintf(stderr, "%d", mx); Solve ( 1, 1, m ) ; fwrite ( Out_buf, iq - Out_buf, 1, stdout ) ; }
第三题:双向搜索, 一道类似的题:集合里找子集,使子集分成两部分加起来的和=0;分出来的两个集合满足可加性,两个双指针扫描;但这道题要两个部分相同,不满足可加性,看起来无法 处理跨集合的情况,两个集合合并的联系是什么?
xi - xj = yi - yj (xi - xj + yj = yi) xi, yj 可取0, 所以每个数我们可以取负,相当于分在前一部分,只要两部分加起来=0说明两部分可以分成两个相同的部分;
#include<bits/stdc++.h> using namespace std; #define rt register #define ll long long const int M = 1e6; ll a[25]; bool legal[1 << 22]; map < ll , vector < int> > mp; void dfs(int dep, int end, int now, ll sum, int d){ if(dep == end + 1){ if(d){ mp[sum].push_back(now); } else { for(vector <int> :: iterator it = mp[-sum].begin() , ed = mp[-sum].end(); it != ed; it++ ) legal[*it | now] = 1; } return ; } dfs(dep + 1, end, now, sum, d); dfs(dep + 1, end, now | ( 1 << (dep - 1) ), sum + a[dep], d); dfs(dep + 1, end, now | ( 1 << (dep - 1) ), sum - a[dep], d); } int main(){ freopen("divide.in","r",stdin); freopen("divide.out","w",stdout); ll ans = 0; int n; scanf("%d", &n); for(int i = 1; i <= n; i++)scanf("%I64d", &a[i]); int len = n / 2; dfs(1, len, 0, 0, 1); dfs(len+1, n, 0, 0, 0); for(int i = 1; i < (1 << n); i++) if(legal[i])ans ++; printf("%I64d", ans); }
第四题:数学化简;
∑(i=0~n) i*C(i, n) = ∑(i = 1~n) n*C(i - 1, n - 1) ==> E(a) = pn;
∑(i=0~n) C(i, n) *p^i *(1 - p)^(n - i) = 1;
==>∑(i=0~n) (i - pn)^2C(i, n)pi ==> np - n*p^2
第二个式子==C(2n,n)
#include<bits/stdc++.h> using namespace std; #define ll long long const ll mod = 1e9 + 7; const int M = 4e6 + 10; ll fac[M]; inline ll moc(ll a){ return a > mod ? a - mod : a;} ll exgcd(ll a, ll b, ll &x, ll &y){ if(!b){x = 1; y = 0; return a;} ll x0 ,y0; ll d = exgcd(b, a%b, x0, y0); x = y0; y = x0 - (a/b)*y0; return x; } ll ni(ll a){ ll x, y; exgcd(a, mod, x, y); return (x%mod + mod) % mod; } int main(){ freopen("mathematics.in","r",stdin); freopen("mathematics.out","w",stdout); fac[0] = 1; for(int i = 1; i <= 4e6; i++) fac[i] = (fac[i - 1] * i) % mod; //print(); int T; scanf("%d", &T); while(T--){ ll n, p; scanf("%I64d%I64d", &n, &p); ll ans = (n * p % mod - n * p % mod * p % mod + mod) % mod; ans = (ans + fac[2*n] * ni(fac[n]) % mod * ni(fac[n]) % mod) % mod; printf("%I64d\n", ans); } }