今天复健赛,只过了三题,太菜了。
A. B-Suffix Array 题目描述 The BB-function $B(t_1 t_2 \dots t_k) = b_1 b_2 \dots b_k$ of a string $t_1 t_2 \dots t_k$ is defined as follows.
If there is an index $j < i$ where $t_j = t_i, b_i = \min_{1 \leq j < i, t_j = t_i}\{i - j\}$,
Otherwise, $b_i = 0$.
Given a string $s_1 s_2 \dots s_n$ , sort its $n$ suffixes into increasing lexicographically order of the BB-function.
Formally, the task is to find a permutaion $p_1, p_2, \dots, p_n$ of $\{1, 2, \dots, n\}$ such that $B(s_{p_{i - 1}} \dots s_n) < B(s_{p_{i}} \dots s_n)$ holds for $i = 2, \dots, n$.
题目分析 大概就是让你对B生成的字符串进行排序,这里 有一份写的很好的题解。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 #include <bits/stdc++.h> using namespace std ;const int maxn=200005 ;namespace Suffix_Array { int sa[maxn],rk[maxn],fir[maxn],sec[maxn],buc[maxn],tmp[maxn],height[maxn]; void fill_buc (int n,int *a) { fill(buc,buc+n+1 ,0 ); for (int i=1 ; i<=n; i++)buc[a[i]]++; for (int i=1 ; i<=n; i++)buc[i]+=buc[i-1 ]; } void build (int n,int *a) { fill_buc(n,a); for (int i=1 ; i<=n; i++)rk[i]=buc[a[i]-1 ]+1 ; for (int t=1 ; t<=n; t<<=1 ) { for (int i=1 ; i<=n; i++) { fir[i]=rk[i]; sec[i]=(i+t)>n?0 :rk[i+t]; } fill_buc(n,sec); for (int i=1 ; i<=n; i++)tmp[n-(--buc[sec[i]])]=i; fill_buc(n,fir); for (int i=1 ; i<=n; i++)sa[buc[fir[tmp[i]]]--]=tmp[i]; bool unique=1 ; for (int j=1 ,last=0 ; j<=n; j++) { int i=sa[j]; if (!last)rk[i]=1 ; else if (fir[i]==fir[last]&&sec[i]==sec[last])rk[i]=rk[last],unique=0 ; else rk[i]=rk[last]+1 ; last=i; } if (unique)break ; } } } using namespace Suffix_Array;int n,b[maxn];string s;struct node { int x,y; node(int _x=0 ,int _y=0 ):x(_x),y(_y) {} bool operator < (const node& b) const { if (y-x==b.y-b.x)return rk[y+1 ]<rk[b.y+1 ]; else return y-x<b.y-b.x; } } a[maxn]; int main () { while (cin >>n>>s) { s=' ' +s; int x=0 ,y=0 ; for (int i=1 ; i<=n; i++) if (s[i]=='a' ) { if (x)b[i]=i-x; else b[i]=0 ; x=i; } else { if (y)b[i]=i-y; else b[i]=0 ; y=i; } for (int i=1 ; i<=n; i++)b[i]++; build(n,b); x=y=n+1 ; for (int i=n; i>=1 ; i--) if (s[i]=='a' ) { a[i]=node(i,y); x=i; } else { a[i]=node(i,x); y=i; } rk[n+1 ]=-1 ,rk[n+2 ]=-2 ; sort(a+1 ,a+n+1 ); for (int i=1 ; i<=n; i++)printf ("%d " ,a[i].x); putchar ('\n' ); } return 0 ; }
题目描述 Bobo has a positive-definite $n \times n$ matrix $A$ and an $n$-dimension vector $b$. He would like to find $x_1, x_2, \dots, x_n$ where
$x_1, x_2, \dots, x_n \in \mathbb{R}$,
$\sum_{i = 1}^n \sum_{j = 1}^n A_{i, j} x_i x_j \leq 1$
$\sum_{i = 1}^n b_i x_i$ is maximum.
It can be shown that $\left(\sum_{i = 1}^n b_i x_i\right)^2 = \frac{P}{Q}$ , which is rational.
Find the value of $P \cdot Q^{-1} \bmod 998244353$.
题目分析 答案就是$b^T A^{-1} b$ 用高斯约旦消元算矩阵的逆即可
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <bits/stdc++.h> using namespace std ;typedef long long LL;const int maxn=405 ,p=998244353 ;int n;LL A[maxn][maxn],tmp[maxn],B[maxn]; LL Quick_Pow (LL a,LL b) { LL sum=1 ; for (; b; b>>=1 ,a=a*a%p)if (b&1 )sum=sum*a%p; return sum; } LL inv (LL x) {return Quick_Pow(x,p-2 );}LL Gauss_Jordan (int n,int m) { LL r=1 ; for (int i=1 ; i<=n; i++) { int row=i; for (; row<=n; row++)if (A[row][i])break ; if (row>n)continue ; if (row!=i) { for (int j=1 ; j<=m; j++)swap(A[i][j],A[row][j]); r=(p-r)%p; } r=r*A[i][i]%p; LL t=inv(A[i][i]); for (int j=1 ; j<=m; j++)A[i][j]=A[i][j]*t%p; for (int j=1 ; j<=n; j++) if (j!=i) { t=A[j][i]; for (int k=1 ; k<=m; k++)A[j][k]=(A[j][k]-t*A[i][k]%p+p)%p; } } return r; } int main () { while (scanf ("%d" ,&n)!=EOF) { memset (A,0 ,sizeof (A)); for (int i=1 ; i<=n; i++) for (int j=1 ; j<=n; j++) { scanf ("%lld" ,&A[i][j]); A[i][j]=(A[i][j]+p)%p; } for (int i=1 ; i<=n; i++)A[i][i+n]=1 ; Gauss_Jordan(n,n<<1 ); for (int i=1 ; i<=n; i++) { scanf ("%lld" ,&B[i]); B[i]=(B[i]+p)%p; } LL ans=0 ; for (int i=1 ; i<=n; i++) { tmp[i]=0 ; for (int j=1 ; j<=n; j++)tmp[i]=(tmp[i]+B[j]*A[i][j+n]%p)%p; ans=(ans+tmp[i]*B[i]%p)%p; } printf ("%lld\n" ,ans); } return 0 ; }
E. Counting Spanning Trees 题目描述 Bobo has a bipartite graph with $(n + m)$ vertices $x_1, x_2, \dots, x_n$ and $y_1, y_2, \dots, y_m$.
The vertex $x_i$ is connected to the first $a_i$ vertices in $Y$, namely $y_1, \dots, y_{a_i}$.
Given $n, m, a_1, \dots, a_n$ and $\mathrm{mod}$, find the number of spanning trees of the graph modulo $\mathrm{mod}$.
题目分析 将结点度数从大到小排序,生成数个数就是$\prod_{i >= 2}^n deg(x_i) \prod_{i >= 2}^m deg(y_i)$
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <bits/stdc++.h> using namespace std ;const int maxn=100005 ;long long da[maxn],db[maxn];int n,m,mod;struct BIT { int c[maxn]; #define lowbit(x) (x&(-x)) void init () { fill(c,c+m+1 ,0 ); } void add (int x,int v) { for (int i=x; i>=1 ; i-=lowbit(i))c[i]+=v; } int query (int x) { int ans=0 ; for (int i=x; i<=m; i+=lowbit(i))ans+=c[i]; return ans; } } bit; int main () { ios::sync_with_stdio(false ); while (cin >>n>>m>>mod) { bit.init(); for (int i=1 ; i<=n; i++) { cin >>da[i]; bit.add(da[i],1 ); } for (int i=1 ; i<=m; i++)db[i]=bit.query(i); sort(da+1 ,da+n+1 ,greater<int >()); sort(db+1 ,db+m+1 ,greater<int >()); long long ans=1 ; for (int i=2 ; i<=n; i++)ans=ans*da[i]%mod; for (int i=2 ; i<=m; i++)ans=ans*db[i]%mod; printf ("%lld\n" ,ans); } return 0 ; }
F. Infinite String Comparision 题目描述 For a string $x$, Bobo defines $x^\infty = x x x \dots$, which is $x$ repeats for infinite times, resulting in a string of infinite length.
Bobo has two strings $a$ and $b$. Find out the result comparing $a^\infty$ and $b^\infty$ in lexicographical order.
You can refer the wiki page for further information of Lexicographical Order.
题目分析 两个串对应$\gcd$的位置必须相同,否则两个串就不同,如果不同暴力比较即可。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <bits/stdc++.h> using namespace std ;int main () { ios::sync_with_stdio(false ); string a,b; while (cin >>a>>b) { int lena=a.length(),lenb=b.length(),posa=0 ,posb=0 ; int gcd=__gcd(lena,lenb); long long lcm=1L L*lena/gcd*lenb; bool flag=0 ; for (int i=0 ; i<lena; i++) { if (a[i%gcd]!=a[i]) flag=1 ; } for (int i=0 ;i<lenb;i++){ if (a[i%gcd]!=b[i]) flag=1 ; } if (flag==0 ) { puts ("=" ); } else { for (int i=0 ; i<lcm; i++) { if (a[posa]<b[posb]) { puts ("<" ); break ; } else if (a[posa]>b[posb]) { puts (">" ); break ; } posa++; posb++; if (posa==lena)posa=0 ; if (posb==lenb)posb=0 ; } } } return 0 ; }
H. Minimum-cost Flow 题目描述 Bobo has a network of $n$ nodes and $m$ arcs. The $i$-th arc goes from the $a_i$-th node to the $b_i$-th node, with cost $c_i$.
Bobo also asks $q$ questions. The $i$-th question is specified by two integers $u_i$ and $v_i$, which is to ask the minimum cost to send one unit of flow from the $1$-th node to the $n$-th node, when all the edges have capacity $\frac{u_i}{v_i}$ (a fraction).
You can refer the wiki page for further information of Minimum-cost Flow.
题目分析 这道题非常机智,可惜我考试的时候没想到是队友想到的。 定义费用流$cost(c,f)$表示容量为$c$,流量为$f$时的费用流总费用。
这样我们就可以把分数容量转化为相对的分数流量,跑网络流就轻松多了。 我们用EK费用流,每次留一个单位的流量,记录下每个单位流量所花费的费用,即可根据不同的询问计算不同的费用,跑一次费用流即可。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include <bits/stdc++.h> using namespace std ;const int maxn=405 ;typedef long long LL;struct Edge { LL from,to,cap,flow,cost; Edge(LL x=0 ,LL y=0 ,LL c=0 ,LL f=0 ,LL co=0 ):from(x),to(y),cap(c),flow(f),cost(co) {} }; LL per[maxn]; struct MinimumCost_MaximumFlow { int n,m; vector <Edge>edges; vector <int >G[maxn]; bool inque[maxn]; LL a[maxn],dist[maxn]; int path[maxn]; void init (int n) { this ->n=n; edges.clear(); for (int i=1 ; i<=n; i++)G[i].clear(); } void AddEdge (int x,int y,LL v,LL f) { edges.push_back(Edge(x,y,v,0 ,f)); edges.push_back(Edge(y,x,0 ,0 ,-f)); m=edges.size(); G[x].push_back(m-2 ); G[y].push_back(m-1 ); } bool bellmanford (int s,int t,LL& flow,LL& cost) { for (int i=1 ; i<=n; i++)dist[i]=LLONG_MAX/2 ; queue <int > Q; Q.push(s); dist[s]=path[s]=0 ; a[s]=LLONG_MAX/2 ; while (!Q.empty()) { int Now=Q.front(); Q.pop(); inque[Now]=0 ; for (int id:G[Now]) { Edge& e=edges[id]; int Next=e.to; if (e.cap>e.flow&&dist[Next]>dist[Now]+e.cost) { dist[Next]=dist[Now]+e.cost; path[Next]=id; a[Next]=min(a[Now],e.cap-e.flow); if (!inque[Next]) { Q.push(Next); inque[Next]=1 ; } } } } if (dist[t]==LLONG_MAX/2 )return false ; flow+=a[t]; cost+=dist[t]*a[t]; for (int Now=t; Now!=s; Now=edges[path[Now]].from) { edges[path[Now]].flow+=a[t]; edges[path[Now]^1 ].flow-=a[t]; } return true ; } LL maxflow (int s,int t,LL& cost) { LL flow=0 ; cost=0 ; while (bellmanford(s,t,flow,cost))per[flow]=cost; return flow; } } mcmf; void printFrac (LL u,LL d) { printf ("%lld/%lld\n" ,u/__gcd(u,d),d/__gcd(u,d)); } int n,m,q;int main () { while (scanf ("%d%d" ,&n,&m)!=EOF) { mcmf.init(n); for (int i=1 ; i<=m; i++) { LL x,y,v; scanf ("%lld%lld%lld" ,&x,&y,&v); mcmf.AddEdge(x,y,1 ,v); } LL cost=0 ; LL flow=mcmf.maxflow(1 ,n,cost); scanf ("%d" ,&q); for (int i=1 ; i<=q; i++) { LL u,v; scanf ("%lld%lld" ,&u,&v); if (flow*u<v) { puts ("NaN" ); continue ; } LL intt=v/u; printFrac(per[intt]*u+(intt==flow?0 :(per[intt+1 ]-per[intt])*(v-intt*u)),v); } } return 0 ; }
I. 1 or 2 题目描述 Bobo has a graph with $n$ vertices and $m$ edges where the $i$-th edge is between the vertices $a_i$ and $b_i$. Find out whether is possible for him to choose some of the edges such that the $i$-th vertex is incident with exactly $d_i$ edges.
题目分析 拆点拆边 对于两边度数都为2的边$e(x,y)$,拆成以下5条边:
$(x, e) (x’, e)$
$(y, e’) (y’, e’)$
$(e, e’)$
然后跑带花树即可
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 #include <bits/stdc++.h> using namespace std ;const int maxn = 100007 ;int head[maxn],nex[maxn],to[maxn],n;int mate[maxn],link[maxn],vis[maxn], fa[maxn];int que[maxn],hd,tl,e1;int read () { int x=0 ,f=1 ; char ch=getchar(); while (ch<'0' ||ch>'9' ) {if (ch=='-' ) f=-1 ;ch=getchar();} while (ch>='0' &&ch<='9' ) x=x*10 +ch-'0' ,ch=getchar(); return x*f; } void addedge (int u,int v) { ++e1;nex[e1]=head[u];head[u]=e1;to[e1]=v; } int find (int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } int LCA (int x,int y) { static int ss[maxn],tim; ++tim; while (ss[x]!=tim){ if (x) {ss[x]=tim;x=find(link[mate[x]]);} swap(x,y); } return x; } void Flower (int x,int y,int p) { while (find(x)!=p){ link[x]=y; fa[y=mate[x]]=(fa[x]=p); if (vis[y]==1 ) vis[que[++tl]=y]=2 ; x=link[y]; } } bool match (int x) { hd=1 ;tl=0 ; for (int i=1 ;i<=n;i++) vis[fa[i]=i]=0 ; vis[que[++tl]=x]=2 ; while (hd<=tl){ x=que[hd++]; for (int i=head[x];i;i=nex[i]) { int u=to[i]; if (!vis[u]){ vis[u]=1 ; link[u]=x; if (!mate[u]){ while (x){ x=mate[link[u]]; mate[mate[u]=link[u]]=u; u=x; } return true ; }else vis[que[++tl]=mate[u]] = 2 ; }else if (vis[u]==2 &&find(u)!=find(x)) { int p=LCA(x,u); Flower(x,u,p); Flower(u,x,p); } } } return false ; } int d[maxn],ans;void init () { for (int i=1 ;i<=n;i++) head[i]=mate[i]=0 ; e1=ans=0 ; } void add (int u,int v) { addedge(u,v);addedge(v,u); if (!mate[u]&&!mate[v]) mate[mate[u]=v]=u,++ans; } int main () { int nn,m; while (scanf ("%d%d" ,&nn,&m)==2 ){ n=nn*2 +m*2 ; init(); int tot=0 ; for (int i=1 ;i<=nn;i++) d[i]=read(),tot+=d[i]; for (int i=1 ;i<=m;i++){ int u,v; scanf ("%d%d" ,&u,&v); add(u,nn*2 +i); if (d[u]==2 ) add(nn*2 +i,u+nn); add(v,nn*2 +m+i); if (d[v]==2 ) add(nn*2 +m+i,v+nn); add(nn*2 +i,nn*2 +m+i); } for (int i=1 ;i<=n;++i) if (!mate[i]&&match(i)) ++ans; if (tot%2 ==0 &&ans==m+tot/2 ) printf ("Yes\n" ); else printf ("No\n" ); } return 0 ; }
J. Easy Integration 题目描述 Given $n$, find the value of $\int_{0}^1 (x - x^2)^n \mathrm{d} x$
It can be proved that the value is a rational number $\frac{p}{q}$.
Print the result as $(p \cdot q^{-1}) \bmod 998244353$.
题目分析 答案是$\frac{(n!)^2}{(2n+1)!}$
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <bits/stdc++.h> using namespace std ;const int maxn = 2e6 +5 ;const long long mo = 998244353 ;long long fac[maxn];long long qpow (long long a,long long b) { long long res = 1 ; while (b) { if (b & 1 ) { res *= a; res %= mo; } a *= a; a %= mo; b >>= 1 ; } return res; } long long inv (long long x) { return qpow(x,mo-2 ); } int main () { fac[1 ] = 1 ; for (int i=2 ;i<maxn;i++) fac[i] = (fac[i-1 ] * i) % mo; long long n; while (scanf ("%lld" ,&n) == 1 ) { long long ans = fac[2 * n + 1 ]; ans = (ans * qpow(inv(fac[n]),2 )) % mo; printf ("%lld\n" ,inv(ans)); } return 0 ; }