2020 省选模拟测试 Round #12 solution (20/02/18)

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

A. 问题求解

【题解】

类欧几里得板子题.

考虑 $m$ 二进制下每一位的贡献,有经典公式 $im$ 的第 $x$ 位为 $\lfloor\frac{im}{2^x}\rfloor-2\lfloor\frac{im}{2^{x+1}}\rfloor$. 类欧几里得即可.

【代码】

 1 #include<bits/stdc++.h>
 2 const int mod=1000000007;
 3 long long n,m,ans[50],Ans;
 4 inline long long LikeGcd ( long long a,long long b,long long c,long long n )
 5 {
 6     long long nx=n%mod,v=b/c%mod*(nx+1)%mod;
 7     if ( !a ) return v;
 8     if ( a>=c ) return (LikeGcd(a%c,b%c,c,n)+v+nx*(nx+1)/2%mod*((a/c)%mod))%mod;
 9     long long T=((__int128)a*n+b)/c-1;
10     return ((T+1)%mod*nx%mod-LikeGcd(c,c-b-1,a,T)+mod)%mod;
11 }
12 signed main()
13 {
14     scanf("%lld%lld",&n,&m);
15     for ( long long w=0;(1LL<<w)<=(m<<1);w++ ) ans[w]=LikeGcd(m,0,1LL<<w,n);
16     for ( long long w=0;(1LL<<w)<=m;w++ ) if ( (m>>w)&1 ) Ans=(Ans+(ans[w]-2*ans[w+1]%mod+mod)%mod*((1LL<<w)%mod))%mod;
17     return !printf("%lld\n",Ans);
18 }
DTOJ4728

B. 子串

【题解】

考虑 hash 判断. 设第 $i$ 位的字母的后一个位置为 $nxt_i$,权值为 $nxt_i-i$,即可 hash.

用可持久化线段树维护 hash 然后直接将所有后缀排序即可. 则答案为 $\frac{n(n+1}{2}-\sum\limits_{i=1}^{n-1} lcp(s_i,s_{i+1})$.

效率 $O(5 n \log^3 n)$. 如果常数非常优秀能过(注意不同二分方式造成的巨大常数差). 卡卡常就过了.

考虑优化,用可持久化块状数组维护即可. 效率 $O(5 n \log n \sqrt n)$.

【代码】

 1 #include<bits/stdc++.h>
 2 inline int read ( void )
 3 {
 4     int x=0;char ch;
 5     while ( !isdigit(ch=getchar()) ) ;
 6     for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
 7     return x;
 8 }
 9 #define maxn 50010
10 #define Hash 1000000007
11 #define HASH unsigned long long
12 struct tree { int ls,rs;HASH val; } t[maxn*30];
13 int n,a[maxn],root[maxn],p[maxn],nxt[maxn],tot;
14 HASH Pow[maxn];std::set<int> s[maxn];
15 inline void modify ( int &k,int fr,int l,int r,int p,HASH w )
16 {
17     t[k=++tot]=t[fr];t[k].val+=w; 
18     if ( l==r ) return;int mid=(l+r)>>1;
19     if ( p<=mid ) modify(t[k].ls,t[fr].ls,l,mid,p,w);
20     else modify(t[k].rs,t[fr].rs,mid+1,r,p,w);
21 }
22 inline HASH query ( int k,int l,int r,int ql,int qr )
23 {
24     if ( !k or ( ql<=l and r<=qr ) ) return t[k].val;
25     HASH res=0;int mid=(l+r)>>1;
26     if ( ql<=mid and t[k].ls ) res+=query(t[k].ls,l,mid,ql,qr);
27     if ( qr>mid and t[k].rs ) res+=query(t[k].rs,mid+1,r,ql,qr);
28     return res;
29 }
30 std::unordered_map<int,HASH> map[maxn];
31 inline HASH Q ( int l,int len )
32 {
33     if ( map[l].count(len) ) return map[l][len];
34     return map[l][len]=query(root[l],1,n,l,l+len-1)*Pow[l];
35 }
36 inline int lcp ( int x,int y )
37 {
38     int l=0,r=n,ans=0,max=n-std::max(x,y)+1;
39     while ( l<=r )
40     {
41         int mid=(l+r)>>1;
42         if ( mid>max ) { r=mid-1;continue; }
43         if ( Q(x,mid)==Q(y,mid) ) l=mid+1,ans=mid;
44         else r=mid-1;
45     }
46     return ans;
47 }
48 int tmp[maxn];
49 inline bool cmp ( int x,int y )
50 {
51     int l=lcp(x,y);
52     if ( x+l>n ) return true;
53     if ( y+l>n ) return false;
54     return (*s[a[x+l]].lower_bound(x))-x<(*s[a[y+l]].lower_bound(y))-y;
55 }
56 inline void solve_sort ( int l,int r )
57 {
58     if ( l==r ) return;
59     int mid=(l+r)>>1;
60     solve_sort(l,mid);solve_sort(mid+1,r);
61     int pos=l-1;
62     for ( int pos1=l,pos2=mid+1;pos<r; )
63         if ( pos2==r+1 ) tmp[++pos]=p[pos1],pos1++;
64         else if ( pos1==mid+1 ) tmp[++pos]=p[pos2],pos2++;
65         else if ( !cmp(p[pos2],p[pos1]) ) tmp[++pos]=p[pos1],pos1++;
66         else tmp[++pos]=p[pos2],pos2++;
67     for ( int i=l;i<=r;i++ ) p[i]=tmp[i];
68 }
69 signed main()
70 {
71     Pow[0]=1;
72     for ( int i=1;i<=50000;i++ ) Pow[i]=Pow[i-1]*Hash;
73     while ( ~scanf("%d",&n) )
74     {
75         tot=root[n+1]=0;
76         for ( int i=1;i<=n;i++ ) s[a[i]=read()].insert(i),p[i]=i;
77         for ( int i=n;i;nxt[a[i]]=i,i-- )
78             if ( nxt[a[i]] ) modify(root[i],root[i+1],1,n,nxt[a[i]],(nxt[a[i]]-i)*Pow[n-i+1]);
79             else root[i]=root[i+1];
80         solve_sort(1,n);
81         long long ans=1LL*n*(n+1)/2;
82         for ( int i=1;i<n;i++ ) ans-=lcp(p[i],p[i+1]);
83         printf("%lld\n",ans);
84         for ( int i=1;i<=n;i++ ) map[i].clear(),s[i].clear(),nxt[i]=0;
85     }
86     return 0;
87 }
DTOJ4723

C. 内凸包

【题解】

显然枚举顶点. 这里枚举内凸包的左下角 $P$. 考虑 $dp$. 设 $f[i][j]$ 表示最后一条边为 $(i,j)$ 的答案. 考虑转移:

当且仅当前一条边 $(j,k)$ 与 $(i,j)$ 围成为凸的且新增加的 $\triangle PIJ$ 里面没有点时可以转移.

显然转移的条件可以用三角前缀和的方式优化(三角形面积),注意处理细节. 即可做到 $O(1)$ 判断. $O(n^3)$ 枚举 $i,j,k$ 转移即可.

效率 $O(Tn^4)$. 注意写的常数即可通过.

观察转移的性质,显然转移是连续的(画图可以发现),因此可以倒序枚举 $j,k$,同时往前跳,效率优化至 $O(n^3)$.

【代码】

 1 #include<bits/stdc++.h>
 2 inline int read ( void )
 3 {
 4     int x=0;char ch;bool f=true;
 5     while ( !isdigit(ch=getchar()) ) if ( ch=='-' ) f=false;
 6     for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
 7     return f ? x : -x ;
 8 }
 9 struct Vector
10 {
11     int x,y,id;double k;
12     Vector(int _x=0,int _y=0){x=_x;y=_y;}
13     inline friend Vector operator - ( const Vector &u,const Vector &v ) { return Vector(u.x-v.x,u.y-v.y); }
14     inline friend int operator * ( const Vector &u,const Vector &v ) { return u.x*v.y-u.y*v.x; }
15     inline int length ( void ) { return x*x+y*y; }
16 } p[60],q[60],P;
17 signed main()
18 {
19     for ( int T=read();T--; )
20     {
21         int n=read(),ans=0;
22         for ( int i=1;i<=n;i++ ) p[i].x=read(),p[i].y=read();
23         std::sort(p+1,p+n+1,[](const Vector &u,const Vector &v){return u.y==v.y ? u.x<v.x : u.y<v.y;});
24         for ( int st=1;st<=n;st++ )
25         {
26             int m=0;P=p[st];
27             for ( int i=st+1;i<=n;i++ ) q[++m]=p[i];
28             std::sort(q+1,q+m+1,[&](const Vector &u,const Vector &v){return (u-P)*(v-P)==0 ? (u-P).length()<(v-P).length() : (u-P)*(v-P)>0 ;});
29             int f[60][60]={0};
30             for ( int i=1;i<=m;i++ )
31             {
32                 int j=i-1;
33                 while ( j and (q[i]-P)*(q[j]-P)==0 ) j--;
34                 bool flag=(j==i-1);
35                 while ( j )
36                 {
37                     int k=j-1;
38                     while ( k and (q[i]-q[j])*(q[k]-q[j])<0 ) k--;
39                     int s=abs((q[i]-P)*(q[j]-P));
40                     if ( k ) s+=f[j][k];
41                     if ( flag ) f[i][j]=s;
42                     ans=std::max(ans,s);j=k;
43                 }
44                 if ( flag ) for ( int j=2;j<=i;j++ ) f[i][j]=std::max(f[i][j],f[i][j-1]);
45             }
46         }
47         printf("%.1lf\n",ans*0.5);
48     }
49     return 0;
50 }
DTOJ4719
posted @ 2020-02-19 15:48  DTOI_RSY  阅读(171)  评论(0编辑  收藏  举报