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


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

    A. 问题求解

    【题解】

    类欧几里得板子题.

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

    【代码】

     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
    ",Ans);
    18 }
    DTOJ4728

    B. 子串

    【题解】

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

    用可持久化线段树维护 hash 然后直接将所有后缀排序即可. 则答案为 $frac{n(n+1}{2}-sumlimits_{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
    ",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)$ 围成为凸的且新增加的 $ riangle 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
    ",ans*0.5);
    48     }
    49     return 0;
    50 }
    DTOJ4719
  • 相关阅读:
    jdk jre jvm 关系
    深入Android开发之--理解View#onTouchEvent
    使用android.view.TouchDelegate扩大View的触摸点击区域
    Android事件分发详解(三)——ViewGroup的dispatchTouchEvent()源码学习
    BitMap 内存使用优化
    android——屏幕适配大全(转载)
    android——ImageLoader添加缓存
    android——混淆打包
    android——仿微拍贷滑动圆形菜单
    android——使用自带录屏工具进行屏幕录像
  • 原文地址:https://www.cnblogs.com/RenSheYu/p/12331587.html
Copyright © 2020-2023  润新知