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

期末考试前还是训了几次,有几道题的题解还是值得补(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\n",s1);
82         else if(s1<s2) printf("Mr. Hdu %lld\n",s2);
83         else printf("Equal %lld\n",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\n",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\n",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\n",ans1,ans2);
175     }
176 }
View Code

 

posted on 2017-06-28 15:59  acphile  阅读(238)  评论(0编辑  收藏  举报