2020 省选模拟测试 Round #15 solution (20/02/25)

【比赛链接】http://59.61.75.5:8018/contest/225

A. 回文

【题解】

PAM裸题. 考虑回文串的一个回文子串,分两类讨论,一类包含最后一个字符即母串后缀,跳回文树即可. 另一类删去首尾两个字符,沿 PAM dfs 一遍即可.

跳回文树时记得打上标记,使子树内节点不再访问,同时保证时间复杂度. 效率 $O(sum n)$. 期望得分:100.

【代码】

 1 #include<bits/stdc++.h>
 2 const int maxn=5000000+10;
 3 char s[maxn];bool vis[maxn];
 4 int T,n,len[maxn],fail[maxn],ch[maxn][26],cnt,last;
 5 long long Ans,ans[maxn];
 6 inline void dfs ( int u,int fr )
 7 {
 8     int dep=0,x=u;vis[x]=true;
 9     while ( fail[x]>1 and !vis[fail[x]] ) x=fail[x],vis[x]=true,dep++;
10     ans[u]=dep+((fr>1)?(ans[fr]+1):0);Ans+=ans[u];
11     for ( int i=0;i<26;i++ ) if ( ch[u][i] ) dfs(ch[u][i],u);
12     x=u;vis[x]=false;
13     while ( dep-- ) x=fail[x],vis[x]=false;
14 }
15 int main()
16 {
17     for ( scanf("%d",&T);T--; )
18     {
19         scanf(" %s",s+1);n=strlen(s+1);Ans=0;
20         last=cnt=0;s[0]='#';fail[0]=1;len[++cnt]=-1;
21         for ( int i=1;i<=n;i++ )
22         {
23             while ( s[i-len[last]-1]!=s[i] ) last=fail[last];
24             if ( !ch[last][s[i]-97] )
25             {
26                 len[++cnt]=len[last]+2;
27                 int j=fail[last];
28                 while ( s[i-len[j]-1]!=s[i] ) j=fail[j];
29                 fail[cnt]=ch[j][s[i]-97];ch[last][s[i]-97]=cnt;
30             }
31             last=ch[last][s[i]-97];
32         }
33         dfs(0,0);dfs(1,1);printf("%lld
",Ans);
34         for ( int i=0;i<=cnt;i++ )
35         {
36             for ( int j=0;j<26;j++ ) ch[i][j]=0;
37             fail[i]=ans[i]=len[i]=0;
38         }
39     }
40     return 0;
41 }
DTOJ4731

B. Sum of Prefix Sums

【题解】

显然考虑点分治. 考虑两条链的答案如何合并.

记 $sum$ 为前缀和,$S$ 为前缀和的和,需要合并的链为 $a,b$,其中 $a$ 长度 $x$,$b$ 长度 $y$. 则有答案为 $S_a+y imes sum_a +S_b$.

显然 $S_b$ 可以单独处理,且 $a$ 一定时 $S_a+y imes sum_a$ 是关于 $y$ 的一次函数. 李超线段树维护即可.

【代码】

 1 #include<bits/stdc++.h>
 2 const int maxn=150000+10;
 3 struct tree { long long a,b; } t[maxn<<2];
 4 struct node { long long val1,val2,sum,l,x; } st[maxn];
 5 int siz[maxn],son[maxn],tp,n,root,dep[maxn],m;
 6 long long a[maxn],ans;bool vis[maxn];
 7 std::vector<int> e[maxn];
 8 #define ls (k<<1)
 9 #define rs (k<<1|1)
10 #define mid ((l+r)>>1)
11 inline void build ( int k,int l,int r )
12 {
13     t[k].a=t[k].b=0;
14     if ( l==r ) return;
15     build(ls,l,mid);build(rs,mid+1,r);
16 }
17 inline void update ( int k,int l,int r,long long a,long long b )
18 {
19     if ( t[k].a*l+t[k].b<=a*l+b and t[k].a*r+t[k].b<=a*r+b ) { t[k].a=a;t[k].b=b;return; }
20     if ( t[k].a*l+t[k].b>=a*l+b and t[k].a*r+t[k].b>=a*r+b ) return;
21     if ( t[k].a*mid+t[k].b<a*mid+b ) std::swap(t[k].a,a),std::swap(t[k].b,b);
22     if ( a<t[k].a ) update(ls,l,mid,a,b);
23     else update(rs,mid+1,r,a,b);
24 }
25 inline long long query ( int k,int l,int r,int x )
26 {
27     if ( l==r ) return t[k].a*x+t[k].b;
28     if ( x<=mid ) return std::max(t[k].a*x+t[k].b,query(ls,l,mid,x));
29     else return std::max(t[k].a*x+t[k].b,query(rs,mid+1,r,x));
30 }
31 #undef ls
32 #undef rs
33 #undef mid
34 inline void getroot ( int u,int fr,int size )
35 {
36     siz[u]=1;son[u]=0;
37     for ( int v:e[u] ) if ( !vis[v] and v!=fr ) getroot(v,u,size),siz[u]+=siz[v],son[u]=std::max(son[u],siz[v]);
38     son[u]=std::max(son[u],size-son[u]);
39     if ( son[u]<son[root] ) root=u;
40 }
41 inline void dfs ( int u,int fr,long long val1,long long val2,long long sum,int rt )
42 {
43     dep[u]=dep[fr]+1;m=std::max(m,dep[u]);siz[u]=1;
44     for ( int v:e[u] ) if ( !vis[v] and v!=fr ) dfs(v,u,val1+sum+a[v],val2+a[v]*dep[u],sum+a[v],rt),siz[u]+=siz[v];
45     if ( siz[u]==1 ) st[++tp]=(node){val1,val2,sum,dep[u],rt};
46 }
47 inline void solve ( int u )
48 {
49     vis[u]=true;tp=0;m=dep[u]=1;
50     for ( int v:e[u] ) if ( !vis[v] ) dfs(v,u,2*a[u]+a[v],a[v]*dep[u],a[u]+a[v],v);
51     st[++tp]=(node){a[u],0,a[u],1,0};st[0].x=st[tp+1].x=-1;
52     for ( int i=1;i<=tp;i++ ) st[i].sum-=a[u];
53     build(1,1,m);
54     for ( int i=1,j;i<=tp;i=j )
55     {
56         for ( j=i;st[j].x==st[i].x;j++ ) ans=std::max(ans,query(1,1,m,st[j].l)+st[j].val1);
57         for ( j=i;st[j].x==st[i].x;j++ ) update(1,1,m,st[j].sum,st[j].val2);
58     }
59     build(1,1,m);
60     for ( int i=tp,j;i>=1;i=j )
61     {
62         for ( j=i;st[j].x==st[i].x;j-- ) ans=std::max(ans,query(1,1,m,st[j].l)+st[j].val1);
63         for ( j=i;st[j].x==st[i].x;j-- ) update(1,1,m,st[j].sum,st[j].val2);
64     }
65     for ( int v:e[u] ) if ( !vis[v] ) root=0,getroot(v,u,siz[v]),solve(root);
66 }
67 signed main()
68 {
69     scanf("%d", &n);
70     for ( int i=1,u,v;i<n;i++ ) scanf("%d%d",&u,&v),e[u].push_back(v),e[v].push_back(u);
71     for ( int i=1;i<=n;i++ ) scanf("%lld",&a[i]);
72     son[0]=n;getroot(1,0,n);solve(root);
73     return !printf("%lld
",ans);
74 }
DTOJ4735

C. Tritwise Mex

【题解】

设 $c=a*b$,记 $a_{i}$ 表示数列 $a$ 所有最低位为 $i$ 的项依序组成的数列,显然有 :

$$c_{0}=a_{1}*b_{1}+a_{1}*b_{2}+a_{2}*b_{1}+a_{2}*b_{2}=(a_{1}+a_{2})*(b_{1}+b_{2})$$

$$c_{1}=a_{0}*b_{0}+a_{0}*b_{2}+a_{2}*b_{0}=(a_{0}+a_{1}+a_{2})*(b_{0}+b_{1}+b_{2})-(a_{1}+a_{2})*(b_{1}+b_{2})-a_{0}*b_{1}-a_{1}*b_{0}$$

$$c_{2}=a_{0}*b_{1}+a_{1}*b_{0}$$

于是可以用 $4$ 次乘法完成一维计算,效率 $O(4^k - 3^k)$.

【代码】

 1 #include<bits/stdc++.h>
 2 inline std::vector<long long> mul ( const std::vector<int> &A,const std::vector<int> &B,int n )
 3 {
 4     if ( n==1 )
 5     {
 6         std::vector<long long> C;
 7         C.push_back(1LL*A[0]*B[0]);
 8         return C;
 9     }
10     n/=3;
11     std::vector<int> A0,B0;
12     for ( int i=0;i<n;i++ ) A0.push_back(A[i+n*2]),B0.push_back(B[i+n*2]);
13     std::vector<long long> C1=mul(A0,B0,n);
14     for ( int i=0;i<n;i++ ) A0[i]+=A[i],B0[i]+=B[i];
15     std::vector<long long> C2=mul(A0,B0,n);
16     for ( int i=0;i<n;i++ ) A0[i]+=A[i+n],B0[i]+=B[i+n];
17     std::vector<long long> C3=mul(A0,B0,n);
18     for ( int i=0;i<n;i++ ) A0[i]-=A[i],B0[i]-=B[i];
19     std::vector<long long> C=mul(A0,B0,n);
20     for ( int i=0;i<n;i++ ) C.push_back(C2[i]-C1[i]);
21     for ( int i=0;i<n;i++ ) C.push_back(C3[i]-C[i]-C[i+n]);
22     return C;
23 }
24 inline int read ( void )
25 {
26     int x=0;char ch;
27     while ( !isdigit(ch=getchar()) ) ;
28     for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
29     return x;
30 }
31 inline void write ( long long x,char ch )
32 {
33     int st[50]={0},tp=0;
34     while ( x ) st[++tp]=x%10,x/=10;
35     if ( !tp ) st[++tp]=0;
36     for ( int i=tp;i;i-- ) putchar(st[i]^48);
37     putchar(ch);
38 }
39 signed main()
40 {
41     int n=read(),m=1;
42     for ( int i=1;i<=n;i++ ) m*=3;
43     std::vector<int> A,B;
44     for ( int i=0;i<m;i++ ) A.push_back(read());
45     for ( int i=0;i<m;i++ ) B.push_back(read());
46     std::vector<long long> C=mul(A,B,m);
47     for ( int i=0;i<m;i++ ) write(C[i]," 
"[i==m-1]);
48     return 0;
49 }
DTOJ4736
原文地址:https://www.cnblogs.com/RenSheYu/p/12364051.html