zoukankan      html  css  js  c++  java
  • 5.20训练的一些题解

    忙完期末考试该回归训练了……

    期末考试前还是训了几次,有几道题的题解还是值得补(mark)一下的

    hdu5321

    比较经典的莫比乌斯反演+组合数学

    具体见http://blog.csdn.net/smilewsw/article/details/47157189

     1 #include<bits/stdc++.h>
     2 #define N 100000
     3 using namespace std;
     4 typedef long long ll;
     5 const int mo=258280327;
     6 vector<int> g[N+5];
     7 int p[N+5],v[N+5],u[N+5],c[N+5],t,n;
     8 ll jc[N+5],d2[N+5],f1[N+5],f2[N+5];
     9 
    10 void init()
    11 {
    12     u[1]=1;
    13     for (int i=2; i<=N; i++)
    14     {
    15         if (!v[i])
    16         {
    17             u[i]=-1;
    18             p[++t]=i;
    19         }
    20         for (int j=1; j<=t; j++)
    21         {
    22             if (i*p[j]>N) break;
    23             v[i*p[j]]=1;
    24             if (i%p[j]==0)
    25             {
    26                 u[i*p[j]]=0;
    27                 break;
    28             }
    29             else u[i*p[j]]=-u[i];
    30         }
    31     }
    32     jc[0]=1; d2[0]=1;
    33     for (int i=1; i<=N; i++)
    34     {
    35         jc[i]=jc[i-1]*i%mo;
    36         d2[i]=d2[i-1]*2%mo;
    37     }
    38     for (int i=1; i<=N; i++)
    39         for (int j=i; j<=N; j+=i)
    40             g[j].push_back(i);
    41 }
    42 
    43 int main()
    44 {
    45     init();
    46     while (scanf("%d",&n)!=EOF)
    47     {
    48         memset(c,0,sizeof(c));
    49         int mx=0,x;
    50         for (int i=1; i<=n; i++)
    51         {
    52             scanf("%d",&x);
    53             mx=max(mx,x);
    54             for (int j=0; j<g[x].size(); j++)
    55                 c[g[x][j]]++;
    56         }
    57         for (int i=1; i<=mx; i++)
    58         {
    59             ll tmp=c[i];
    60             f1[i]=0;
    61             f2[i]=d2[c[i]-1]*c[i]%mo;
    62             for (int j=1; j<=c[i]; j++)
    63             {
    64                 f1[i]=(f1[i]+tmp*jc[n-j+1]%mo)%mo;
    65                 tmp=tmp*(c[i]-j)%mo;
    66             }
    67         }
    68         ll s1=0,s2=0;
    69         for (int i=1; i<=mx; i++)
    70         {
    71             ll t1=0,t2=0;
    72             for (int j=i; j<=mx; j+=i)
    73             {
    74                 t1=(t1+f1[j]*u[j/i]%mo)%mo;
    75                 t2=(t2+f2[j]*u[j/i]%mo)%mo;
    76             }
    77             s1=(s1+t1*i%mo)%mo;
    78             s2=(s2+t2*i%mo)%mo;
    79         }
    80         s1=(s1+mo)%mo; s2=(s2+mo)%mo;
    81         if (s1>s2) printf("Mr. Zstu %lld
    ",s1);
    82         else if(s1<s2) printf("Mr. Hdu %lld
    ",s2);
    83         else printf("Equal %lld
    ",s2);
    84     }
    85 }
    View Code

    hdu5322

    记ans[i]为所有1,2,...,i的排列的permutation value之和,

    考虑i的位置,当i位于第j个位置时,前j个点是连通的,且后i-j个点与前j个点不连通

    这里对答案的贡献为C(i-1,j-1)*(j-1)!*j^2*ans[i-j],

    不妨设dp[0]=1 则ans[i]=∑(C(i-1,j-1)*(j-1)!*j^2*ans[i-j])

    然后就是经典的分治+ntt优化

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 typedef long long ll;
     5 const int mo=998244353;
     6 const int g=3;
     7 const int maxn=1e5;
     8 int ta[400010],tb[400010],w[30][2],rg[30],r[400010],d[100010],n;
     9 ll ans[100010],jc[100010],ni[100010];
    10 ll quick(ll x,int y)
    11 {
    12     ll s=1;
    13     while (y)
    14     {
    15         if (y&1) s=s*x%mo;
    16         x=x*x%mo;
    17         y>>=1;
    18     }
    19     return s;
    20 }
    21 
    22 void ntt(int *a,int n,int f)
    23 {
    24     for (int i=0; i<n; i++)
    25         if (i<r[i]) swap(a[i],a[r[i]]);
    26     int now=0;
    27     for (int i=1; i<n; i<<=1)
    28     {
    29         int p=w[++now][f];
    30         for (int j=0; j<n; j+=i<<1)
    31         {
    32             ll w=1;
    33             for (int k=0; k<i; k++)
    34             {
    35                 int u=a[k+j],v=w*a[j+k+i]%mo;
    36                 a[j+k]=(u+v)%mo;
    37                 a[j+k+i]=(u-v+mo)%mo;
    38                 w=w*p%mo;
    39             }
    40         }
    41     }
    42 }
    43 
    44 void solve(int h,int t)
    45 {
    46     int m=t-h+1,mid=(h+t)>>1;
    47     int n,l=0;
    48     for (n=1; n<=m; n<<=1) l++;
    49     for (int i=0; i<n; i++)
    50     {
    51         r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    52         ta[i]=tb[i]=0;
    53     }
    54     for (int i=h; i<=mid; i++) ta[i-h]=ans[i]*ni[i]%mo;   // j
    55     for (int i=0; i<=m; i++) tb[i]=d[i];  // i-j
    56     ntt(ta,n,1); ntt(tb,n,1);
    57     for (int i=0; i<=n; i++) ta[i]=1ll*ta[i]*tb[i]%mo;
    58     ntt(ta,n,0);
    59     for (int i=mid+1; i<=t; i++)
    60         ans[i]=(ans[i]+jc[i-1]*ta[i-h]%mo*rg[l]%mo)%mo;
    61 }
    62 
    63 void work(int l,int r)
    64 {
    65     if (l==r) return;
    66     int m=(l+r)>>1;
    67     work(l,m);
    68     solve(l,r);
    69     work(m+1,r);
    70 }
    71 
    72 int main()
    73 {
    74     int now=(mo-1)/2,ng=quick(g,mo-2),l=0;
    75     while (now%2==0)
    76     {
    77         w[++l][1]=quick(g,now);
    78         w[l][0]=quick(ng,now);
    79         rg[l]=quick(1<<l,mo-2);
    80         now>>=1;
    81     }
    82     jc[0]=1; ni[0]=1;
    83     for (int i=1; i<=maxn; i++)
    84     {
    85         jc[i]=jc[i-1]*i%mo;
    86         ni[i]=quick(jc[i],mo-2);
    87         d[i]=1ll*i*i%mo;
    88     }
    89     ans[0]=1;
    90     work(0,100000);
    91     //cout <<ans[2]<<endl;
    92     while (scanf("%d",&n)!=EOF) printf("%lld
    ",ans[n]);
    93 }
    View Code

    hdu5324

    三维偏序关系的最长上升子序列

    经典的cdq分治,唯一值得注意的是这题要求字典序最小的序列

    我们可以从后面往前做分治,以每个点为起点,最长延伸多长就可以了

      1 #include<bits/stdc++.h>
      2 
      3 #define fi first
      4 #define se second
      5 #define pi pair<int,int>
      6 #define mp make_pair
      7 
      8 using namespace std;
      9 struct node{int x,y,id;} a[50010],aa[50010];
     10 pi c[50010],f[50010];
     11 int q[50010],v[50010],b[50010],n,m,t;
     12 
     13 bool cmp(node a,node b)
     14 {
     15     return (a.y>b.y)||(a.y==b.y&&a.id>b.id);
     16 }
     17 
     18 void up(int x,int y)
     19 {
     20     for (int i=x; i<=m; i+=i&(-i))
     21     {
     22         if (c[i].fi<f[y].fi||(c[i].fi==f[y].fi&&c[i].se>y))
     23             c[i]=mp(f[y].fi,y);
     24         if (!v[i])
     25         {
     26             q[++t]=i;
     27             v[i]=1;
     28         }
     29     }
     30 }
     31 
     32 void ask(int x,int y)
     33 {
     34     for (int i=x; i; i-=i&(-i))
     35     {
     36         if (c[i].fi+1>f[y].fi||(c[i].fi+1==f[y].fi&&c[i].se<f[y].se))
     37             f[y]=mp(c[i].fi+1,c[i].se);
     38     }
     39 }
     40 
     41 void work(int l,int r)
     42 {
     43     if (l==r)
     44         return;
     45     int mid=(l+r)>>1;
     46     work(mid+1,r);
     47     for (int i=l; i<=r; i++) aa[i]=a[i];
     48     sort(aa+l,aa+r+1,cmp);
     49     t=0;
     50     for (int i=l; i<=r; i++)
     51     {
     52         if (aa[i].id>mid) up(aa[i].x,aa[i].id);
     53         else ask(aa[i].x,aa[i].id);
     54     }
     55     for (int i=1; i<=t; i++)
     56     {
     57         int x=q[i];
     58         c[x]=mp(0,-1);
     59         v[x]=0;
     60     }
     61     work(l,mid);
     62 }
     63 
     64 int main()
     65 {
     66     while (scanf("%d",&n)!=EOF)
     67     {
     68         for (int i=1; i<=n; i++)
     69             scanf("%d",&a[i].x);
     70         for (int i=1; i<=n; i++)
     71         {
     72             scanf("%d",&a[i].y);
     73             b[i]=a[i].x;
     74             a[i].id=i;
     75         }
     76         memset(v,0,sizeof(v));
     77         sort(b+1,b+1+n);
     78         m=unique(b+1,b+1+n)-b-1;
     79         for (int i=1; i<=n; i++)
     80         {
     81             a[i].x=lower_bound(b+1,b+1+m,a[i].x)-b;
     82             f[i]=mp(1,-1);
     83         }
     84         for (int i=1; i<=m; i++)
     85             c[i]=mp(0,-1);
     86         int ans=0;
     87         work(1,n);
     88 
     89         for (int i=1; i<=n; i++)
     90             if (f[i].fi>f[ans].fi) ans=i;
     91         int len=f[ans].fi;
     92         printf("%d
    ",len);
     93         printf("%d",ans);
     94         for (int i=2; i<=len; i++)
     95         {
     96             printf(" %d",f[ans].se);
     97             ans=f[ans].se;
     98         }
     99         puts("");
    100     }
    101 }
    View Code

    hdu5320

    好久没写题代码能力简直贫弱

    这道题思路不难,写起来有点麻烦

    首先以某个点为右端点的区间的gcd种类级别是log的(因为下降最少是除2)

    预处理所有的四元组(g,l,r,x)表示以x为右端点,左端点在[l,r]内区间公约数都是g

    然后以g为第一关键字,x为第二关键字即可

    最多选取不相邻区间数dp+线段树

    计算方案要考虑两种情况,dp[i]=dp[j]+1

    一是j落在[l,r-1],二是j落在[1,l-1],这两种i选取的方案是不一样的

    然后就没了

      1 #include<bits/stdc++.h>
      2 #define mp make_pair
      3 #define fi first
      4 #define se second
      5 #define pi pair<int,int>
      6 using namespace std;
      7 typedef long long ll;
      8 const int mo=998244353;
      9 struct node{int w,l,r,x;} q[100010*30];
     10 struct po{int a,b,c;} mx[100010*4],null;
     11 pi g[2][100010];
     12 int st[100010*4],a[100010],n,t,tt,b[5],cas,ans1,ans2;
     13 bool v[100010*4];
     14 
     15 int gcd(int a,int b)
     16 {
     17     return (b==0)?a:gcd(b,a%b);
     18 }
     19 
     20 void inc(int &a,int b)
     21 {
     22     a+=b;
     23     if (a>mo) a-=mo;
     24 }
     25 
     26 bool cmp(node a,node b)
     27 {
     28     if (a.w==b.w) return a.x<b.x;
     29     return a.w<b.w;
     30 }
     31 
     32 void init()
     33 {
     34     int p=0;
     35     q[1]=(node){a[1],1,1,1};
     36     b[0]=1;
     37     g[0][1]=mp(1,a[1]);
     38     for (int i=2; i<=n; i++)
     39     {
     40         p^=1; b[p]=1; g[p][1]=mp(i,a[i]);
     41         int gg=a[i];
     42         for (int j=1; j<=b[p^1]; j++)
     43         {
     44             pi tmp=g[p^1][j];
     45             gg=gcd(tmp.se,gg);
     46             if (g[p][b[p]].se==gg) g[p][b[p]].fi=tmp.fi;
     47             else g[p][++b[p]]=mp(tmp.fi,gg);
     48         }
     49         q[++t]=(node){g[p][1].se,g[p][1].fi,i,i};
     50         for (int j=2; j<=b[p]; j++)
     51             q[++t]=(node){g[p][j].se,g[p][j].fi,g[p][j-1].fi-1,i};
     52     }
     53     sort(q+1,q+1+t,cmp);
     54 }
     55 
     56 void up(po &a,po b,po c)
     57 {
     58     if (b.a>c.a) a=b;
     59     else {
     60         a=c;
     61         if (b.a==c.a)
     62         {
     63             inc(a.b,b.b);
     64             inc(a.c,b.c);
     65         }
     66     }
     67 }
     68 
     69 po ask(int i,int l,int r,int x,int y)
     70 {
     71     if (y<x||x<1) return null;
     72     if (x<=l&&y>=r) return mx[i];
     73     int m=(l+r)>>1;
     74     po c;
     75     if (x<=m&&y<=m) return ask(i*2,l,m,x,y);
     76     else if (y>m&&x>m) return ask(i*2+1,m+1,r,x,y);
     77     else {
     78         up(c,ask(i*2,l,m,x,y),ask(i*2+1,m+1,r,x,y));
     79         return c;
     80     }
     81 }
     82 
     83 void add(int i,int l,int r,int f1,int f2,int x)
     84 {
     85     if (!v[i])
     86     {
     87         st[++tt]=i;
     88         v[i]=1;
     89     }
     90     if (l==r)
     91     {
     92         mx[i]=(po){f1,f2,(ll)l*f2%mo};
     93         return;
     94     }
     95     int m=(l+r)>>1;
     96     if (x<=m) add(i*2,l,m,f1,f2,x);
     97     else add(i*2+1,m+1,r,f1,f2,x);
     98     up(mx[i],mx[i*2],mx[i*2+1]);
     99 }
    100 
    101 void work(int l,int r)
    102 {
    103     tt=0;
    104     if (ans1>r-l+1) return;
    105     add(1,1,n,1,q[l].r-q[l].l+1,q[l].x);
    106     int s1=1,s2=q[l].r-q[l].l+1;
    107     for (int i=l+1; i<=r; i++)
    108     {
    109         int f1,f2;
    110         po m1=ask(1,1,n,1,q[i].l-1);
    111         po m2=ask(1,1,n,q[i].l,q[i].r-1);
    112         if (!m1.a&&!m2.a)
    113         {
    114             f1=1;
    115             f2=q[i].r-q[i].l+1;
    116         }
    117         else if (m1.a>m2.a)
    118         {
    119             f1=m1.a+1;
    120             f2=(ll)(q[i].r-q[i].l+1)*m1.b%mo;
    121         }
    122         else {
    123             f1=m2.a+1;
    124             f2=(1ll*q[i].r*m2.b%mo-m2.c+mo)%mo;
    125             if (m1.a==m2.a) inc(f2,(ll)(q[i].r-q[i].l+1)*m1.b%mo);
    126         }
    127         if (s1<f1)
    128         {
    129             s1=f1;
    130             s2=f2;
    131         }
    132         else if (s1==f1) inc(s2,f2);
    133         add(1,1,n,f1,f2,q[i].x);
    134     }
    135     for (int i=1; i<=tt; i++)
    136     {
    137         int x=st[i];
    138         mx[x]=null;
    139         v[x]=0;
    140     }
    141     if (s1>ans1) {ans1=s1; ans2=s2;}
    142     else if (s1==ans1) inc(ans2,s2);
    143 }
    144 
    145 void build(int i,int l,int r)
    146 {
    147     mx[i]=null;
    148     if (l!=r)
    149     {
    150         int m=(l+r)>>1;
    151         build(i*2,l,m);
    152         build(i*2+1,m+1,r);
    153     }
    154 }
    155 
    156 int main()
    157 {
    158     null=(po){0,0,0};
    159     build(1,1,100000);
    160     memset(v,0,sizeof(v));
    161     while (scanf("%d",&n)!=EOF)
    162     {
    163         for (int i=1; i<=n; i++) scanf("%d",&a[i]);
    164         t=1; init();
    165         int i=1; ans1=0; ans2=0;
    166         tt=0;
    167         while (i<=t)
    168         {
    169             int j=i+1;
    170             while (j<=t&&q[j].w==q[i].w) j++;
    171             work(i,j-1);
    172             i=j;
    173         }
    174         printf("%d %d
    ",ans1,ans2);
    175     }
    176 }
    View Code
  • 相关阅读:
    [转]用异或交换两个整数的陷阱
    线索化二叉树
    [转]Socket编程中,阻塞与非阻塞的区别
    两个链表的归并
    [转] std::string and stl 算法
    类图
    leetcode 答案
    about raw socket
    54. Spiral Matrix【数组】
    矩阵乘法问题的实现
  • 原文地址:https://www.cnblogs.com/phile/p/7090146.html
Copyright © 2011-2022 走看看