2020 省选模拟测试 Round #14 solution (20/02/22)

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

A. 雕像

【题解】

一般最大最小问题可用二分解决,而和的最小值/最大值类问题可用 dp 凸优化(wqs 二分)解决.

外层使用 dp 凸优化,内层 dp 符合要求覆盖所有村庄需要的最少雕像个数,由于满足四边形不等式,单调队列+二分优化 dp 即可.

效率 $O(n \log n \log \sum\limits_{i=1}^n a_i)$.

【代码】

 1 #include<bits/stdc++.h>
 2 const long long inf=1LL<<60;
 3 const int maxn=300000+10;
 4 long long sum[maxn],f[maxn];
 5 int a[maxn],g[maxn],q[maxn],pos[maxn],n,k;
 6 inline long long query ( int l,int r ) { return sum[l-1]+sum[r]-sum[(l+r)/2]-sum[(l+r-1)/2]; }
 7 inline void solve ( long long k )
 8 {
 9     for ( int i=1;i<=n;i++ ) f[i]=inf,g[i]=q[i]=pos[i]=0;
10     int l=1,r=1;pos[1]=n;
11     for ( int i=1;i<=n;i++ )
12     {
13         while ( l<r and pos[l]<=i ) l++;
14         f[i]=f[q[l]]+query(q[l]+1,i)+k;
15         g[i]=g[q[l]]+1;
16         while ( l<r )
17         {
18             long long lst=f[q[r]]+query(q[r]+1,pos[r-1]);
19             long long res=f[i]+query(i+1,pos[r-1]);
20             if ( lst<res or ( lst==res and g[q[r]]<=g[i] ) ) break;
21             r--;
22         }
23         int ll=q[r],rr=n+1;
24         while ( ll<rr )
25         {
26             int mid=(ll+rr)>>1;
27             long long lst=f[q[r]]+query(q[r]+1,mid);
28             long long res=f[i]+query(i+1,mid);
29             if ( lst>res or ( lst==res and g[q[r]]>g[i] ) ) rr=mid;
30             else ll=mid+1;
31         }
32         pos[r]=ll;q[++r]=i;
33     }
34 }
35 signed main()
36 {
37     scanf("%d%d",&n,&k);
38     for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
39     long long l=0,r=sum[n];
40     while ( l<r )
41     {
42         long long mid=(l+r)>>1;
43         solve(mid);
44         if ( g[n]>k ) l=mid+1;
45         else r=mid;
46     }
47     solve(l);
48     return !printf("%lld\n",f[n]-k*l);
49 }
DTOJ4721

 B. 函数

【题解】

显然 $H(d)=\prod\limits_{p\text{ is prime}} g(p,d)$ 是积性函数。由二平方和定理(打表找规律)可知 $H(p^e)=3e+1\,(p\equiv 1\pmod 4)$,Min_25 筛即可.

【代码】

 1 #include<bits/stdc++.h>
 2 long long n,m,pr[100000],tot,Pow[100000],g[100000],S1[100000][5],S2[100000][5],sum1[100000],sum2[100000];
 3 bool flag[100000];
 4 inline long long f ( long long p,long long k ) { return (p%4==1) ? 3*k+1 : 1 ; }
 5 inline long long Min_25 ( long long x,long long k )
 6 {
 7     if ( x<=1 or pr[k]>x ) return 0;
 8     long long ans=((x<=m)?sum1[x]:sum2[n/x])-Pow[k-1];
 9     for ( long long i=k;i<=tot and pr[i]*pr[i]<=x;i++ ) for ( long long v=pr[i],j=1;v*pr[i]<=x;v*=pr[i],j++ ) ans+=Min_25(x/v,i+1)*f(pr[i],j)+f(pr[i],j+1);
10     return ans;
11 }
12 signed main()
13 {
14     long long T;
15     for ( scanf("%lld",&T);T--; )
16     {
17         scanf("%lld",&n);m=(long long)sqrt(n);
18         for ( long long i=1;i<=m;i++ ) flag[i]=true;
19         flag[1]=false;tot=0;
20         for ( long long i=2;i<=m;i++ )
21         {
22             if ( flag[i] ) pr[++tot]=i,Pow[tot]=Pow[tot-1]+((i%4==1)?4:1);
23             for ( long long j=1;j<=tot and pr[j]*i<=m;j++ )
24             {
25                 flag[i*pr[j]]=false;
26                 if ( !(i%pr[j]) ) break;
27             }
28         }
29         for ( long long i=1;i<=n;i=n/(n/(i+1)) )
30         {
31             if ( i<=m ) for ( long long j=0;j<4;j++ ) S1[i][j]=(i-1)/4+((i-1)%4>=(j+3)%4);
32             else for ( long long j=0;j<4;j++ ) S2[n/i][j]=(i-1)/4+((i-1)%4>=(j+3)%4);
33             if ( i==n ) break;
34         }
35         for ( long long i=1;i<=tot;i++ )
36         {
37             long long p=pr[i],p2=p*p;
38             for ( long long a=n;a>=p2;a=n/(n/a+1) ) for ( long long j=0;j<4;j++ )
39                 if ( a<=m )
40                 {
41                     if ( a/p<=m ) S1[a][p*j%4]-=S1[a/p][j]-S1[p-1][j];
42                     else S1[a][p*j%4]-=S2[n/(a/p)][j]-S1[p-1][j];
43                 }
44                 else
45                 {
46                     if ( a/p<=m ) S2[n/a][p*j%4]-=S1[a/p][j]-S1[p-1][j];
47                     else S2[n/a][p*j%4]-=S2[n/(a/p)][j]-S1[p-1][j];
48                 }
49         }
50         for ( long long i=1;i<=n;i=n/(n/(i+1)) )
51         {
52             if ( i<=m ) S1[i][1]--;
53             else S2[n/i][1]--;
54             if ( i==n ) break;
55         }
56         for ( long long i=1;i<=n;i=n/(n/(i+1)) )
57         {
58             if ( i<=m ) sum1[i]=4*S1[i][1]+S1[i][3]+1;
59             else sum2[n/i]=4*S2[n/i][1]+S2[n/i][3]+1;
60             if ( i==n ) break;
61         }
62         printf("%lld\n",Min_25(n,1)+1);
63     }
64     return 0;
65 }
DTOJ4721

C. Incomparable Pairs

【题解】

考虑容斥,计算子串 $a$ 为子串 $b$ 的子串数量.

对 $s$ 建 SAM,对于每一个一个本质不同的子串,计算它包含的本质不同的子串个数之和就是答案.

一个子串可能出现多次,任意选取一次就可以计算答案. 而对于自动机上的一个节点,它产生的贡献为 $s_{\min,r},s_{\min+1,r},\dots,s_{\max,r}$ 中的本质不同的子串.

设 $p_i$ 表示从 $i$ 开始,到现在 $r$ 的本质不同子串的个数(位置不同的相同子串只记录最后一次),可以对每一个本质不同的字串,在它最后一次出现的左端点 $+1$.

每插入一个字符,就算一次新增的自动机节点的贡献,当 $r$ 变大的时候,在 parent 树上从新增节点到根的最后出现位置都会更改。相当于把 parent 树上这一条链染色. 用 LCT 维护.

发现我们要求的是后缀和后的区间和,可以在线段树上区间加等差数列.

发现 SAM 上节点可能分裂,这里查询答案的时候用原来的大小,查询这个节点原来的 $[R-\max+1,R-\min+1]$. 累加就是答案.

效率 $O(n \log^2 n)$.

猜你喜欢

转载自www.cnblogs.com/RenSheYu/p/12354665.html