忙完期末考试该回归训练了……
期末考试前还是训了几次,有几道题的题解还是值得补(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 }
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 }
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 }
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 }