20191023+~20191028
前言
- 落下了很久的博客,稍补一下。
- 由于我的记忆力很差只能记住一天以内的考试,所以n天前的考试我是差不多忘光了。
- 所以与其说是题解,更不如说坑点总结和吐槽合集……
20191023+
T1
- 直接模拟,如何去重应该很好想到。
- 但是我的确是不知道为什么一个优先队列会比u15个队列慢这么多……logK和15应该差不多啊。
- 然而事实上我在意淫优先队列每次也要扩展15个点所以复杂度是多了个log。
- 时间复杂度$\Theta(KB)$,空间复杂度稍玄学,反正用数组模拟队列会MLE,必须动态分配内存。
#include<cstdio> #include<queue> using namespace std; #define ll long long ll const N=1e18+1; const int p[16]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47}; int k,b; queue<ll>q[16]; inline ll min(ll x,ll y){ return x<y?x:y; } inline void work1(){ for(register int i=1;i<=b;++i)q[i].push(p[i]); const int lt=k-1; int t(0); while(++t!=lt){ ll y=N; int x=0; for(register int i=1;i<=b;++i) if(q[i].front()<y)y=q[i].front(),x=i; q[x].pop(); for(register int i=x;i;--i) if(y*p[i]<N)q[i].push(y*p[i]); } ll y=N; for(register int i=1;i<=b;++i) y=min(y,q[i].front()); printf("%lld",y); } int main(){ //freopen("1.in","r",stdin); scanf("%d%d",&b,&k); work1(); return 0; }
T2
- 8进制压缩状态,记忆化搜索。
- 注意位运算的优先级……调了一早。
- 复杂度玄学。
#include<cstdio> #include<cmath> #define ll long long using namespace std; int const mod=1e9+7; ll n,p[7]; int ct[7],bs[1<<5|1]; ll ym[1<<6]; int t,lt,ans; ll f[1<<18]; inline int down(int x){ return x<mod?x:x-mod; } inline int set(int x,int y,int z){ return (x&(~(7<<y*3)))|(z<<y*3); } inline int at(int x,int y){ return (x>>(y-1)*3)&7; } inline bool find(int x,int y){ for(register int i=y,la=0,j,z;i;i-=i&-i){ if((z=at(x,bs[i&-i]))==7)return 0; if(z){ if(la && la!=z)return 0; la=z; } } return 1; } inline int Get(int x,int y){ int z(0); for(register int i=y;i;i-=i&-i) if(!at(x,bs[i&-i])) {z=bs[i&-i];break;} for(register int i=y;i;i-=i&-i) x=set(x,bs[i&-i]-1,at(x,bs[i&-i])?7:z); return x< } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%lld",&n); int lit=sqrt(n); for(register int i=2;i<=lit&&n^1;++i) if(!(n%i)){ p[++t]=i; do n/=i,++ct[t];while(!(n%i)); } if(n^1)p[++t]=n,ct[t]=1; for(register int i=1;i<=t;++i)bs[1<<i-1]=i; lit=1<<t; for(register int i=1;i<lit;++i){ ym[i]=1; for(register int j=i;j;j-=j&-j) ym[i]=ym[i]*ct[bs[j&-j]]; } f[0]=1; lt=(1<<t*3)-1; for(register int i=0;i<lt;++i){ if(!f[i])continue; for(register int j=1,now=f[i];j<lit;++j) if(find(i,j))(f[Get(i,j)]+=ym[j]*now)%=mod; } for(register int i=1;i<=lt;++i)ans=down(ans+f[i]); printf("%d",ans); return 0; }
T3
- 正解随机化的神题。
- 其实很好实现,就是spj比较坑,角度必须是$[0,2\pi]$。
- 还有题中说了scale的范围是(0,10],记得调对……我调了一晚上。
- 在解出一组解前一直随机化,所以复杂度更玄学……(出题人钛聚勒出了三道玄学题)。
#include<bits/stdc++.h> #define db double using namespace std; int const N=1e5+5,M=5; db const eps=1e-3,pi=3.141592653589793238462; int n; db a[N],b[N],c[N],d[N]; db s[5][6],ans[5]; inline db _abs(db x){ return x<0?-x:x; } inline void _swap(db &x,db &y){ db z=x; x=y,y=z; return ; } inline void gauss(){ for(register int i=1,z=1;i<M;z=++i){ for(register int j=i+1;j<M;++j) if(_abs(s[j][i])>_abs(s[z][i]))z=j; if(_abs(s[z][i])>=eps){ for(register int j=1;j<=M;++j)_swap(s[i][j],s[z][j]); for(register int j=i+1;j<M;++j) if(_abs(s[j][i])>=eps){ double zz=s[j][i]/s[i][i]; for(register int k=i;k<=M;++k) s[j][k]-=zz*s[i][k]; } } else return ; } for(register int i=M-1;i;--i){ for(register int j=i+1;j<M;++j) s[i][M]-=s[i][j]*ans[j]; ans[i]=s[i][M]/s[i][i]; } return ; } int main(){ //freopen("walker18.in","r",stdin); //freopen("1.out","w",stdout); scanf("%d",&n); for(register int i=1;i<=n;++i){ double A,B,C,D; scanf("%lf%lf%lf%lf",&A,&B,&C,&D); a[i]=A,b[i]=B,c[i]=C,d[i]=D; } mt19937 rd(time(NULL)); int lit=n+1>>1; while(1){ int x=rd()%n+1,y=rd()%n+1; while(y==x)y=rd()%n+1; s[1][1]=b[y],s[1][2]=a[y],s[1][3]=0,s[1][4]=1,s[1][5]=d[y]; s[2][1]=b[x],s[2][2]=a[x],s[2][3]=0,s[2][4]=1,s[2][5]=d[x]; s[3][1]=a[y],s[3][2]=-b[y],s[3][3]=1,s[3][4]=0,s[3][5]=c[y]; s[4][1]=a[x],s[4][2]=-b[x],s[4][3]=1,s[4][4]=0,s[4][5]=c[x]; gauss(); double ss=sqrt((long double)(ans[1]*ans[1]+ans[2]*ans[2])); double zz=acos(((long double)ans[1]/(long double)ss)); double cs=cos(zz),si=sin(zz); double zas=ans[3],zaa=ans[4]; int ct=0; for(register int j=1;j<=n;++j) if(_abs(ss*(a[j]*cs-b[j]*si)+zas-c[j])<=eps && _abs(ss*(a[j]*si+b[j]*cs)+zaa-d[j])<=eps)++ct; while(zz<0)zz+=pi*2; while(ss<0)zz+=pi,ss=-ss; if(ct>=lit)return printf("%.14lf\n%.14lf\n%.14lf %.14lf",zz,ss,zas,zaa),0; ct=0; ss=-ss; zz=acos(((long double)ans[1]/(long double)ss)); cs=cos(zz),si=sin(zz); for(register int j=1;j<=n;++j) if(_abs(ss*(a[j]*cs-b[j]*si)+zas-c[j])<=eps && _abs(ss*(a[j]*si+b[j]*cs)+zaa-d[j])<=eps)++ct; while(zz<0)zz+=pi*2; while(ss<0)zz+=pi,ss=-ss; if(ct>=lit)return printf("%.14lf\n%.14lf\n%.14lf %.14lf",zz,ss,zas,zaa),0; } return 0; }
20191024
T1
- 模拟题。
- 注意没有spj,所以多个前导0中间用‘+’号连接而不是‘-’。
- 时空复杂度$\Theta(S)$。
#include<cstdio> #include<cstring> using namespace std; int n; char s[100005]; int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%s",s+1); n=strlen(s+1); register int i=1; while(i<=n && s[i]!='-' && s[i]!='+')putchar(s[i++]); for(;i<=n;) if(s[i]=='-'){ putchar('-'); int la=++i; while(i<=n && s[i]!='+' && s[i]!='-')++i; putchar(s[la]); for(register int j=la+1;j<i;++j) if(s[j]=='0')putchar('+'),putchar(48); else{ putchar('+'); while(j<i)putchar(s[j++]); } } else{ putchar('+'),++i; while(i<=n && s[i]!='+' && s[i]!='-')putchar(s[i++]); } return 0; }
T2
- 建出图的dfs树,那么原图上的每条非树边和dfs树都会形成一个环。
- 分情况讨论后可得由两条以上的非树边组成的环可以忽略不考虑。
- 而非树边肯定都是反祖边(dfs时有反祖边就搜回去了),简单树上差分即可。
- 然而我并没有考虑是不是反祖边,直接倍增求lca差分的,复杂度多个log。
- 时空复杂度$\Theta(NlogN)$。
#include<cstdio> #include<cstring> using namespace std; int const N=1e5+5,M=N<<2; int n,m,le,ans; int head[N],Next[M],to[M],t=1; bool vis[N],v[M]; int os[N],js[N]; int dep[N],Log[N],f[N][19]; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline void add(int x,int y){ to[++t]=y; Next[t]=head[x],head[x]=t; return ; } void dfs(int x){ vis[x]=1; for(int i=head[x],y,dnow=dep[x]+1;i;i=Next[i]) if(!vis[y=to[i]]){ v[i]=v[i^1]=1; f[y][0]=x,dep[y]=dnow; for(register int j=0;j<Log[dnow];++j) f[y][j+1]=f[f[y][j]][j]; dfs(y); } return ; } inline void _Swap(int &x,int &y){ int z=x; x=y,y=z; return ; } inline int lca(int x,int y){ if(dep[x]<dep[y])_Swap(x,y); for(register int i=Log[dep[x]];~i;--i) if(dep[f[x][i]]>=dep[y])x=f[x][i]; if(x==y)return x; for(register int i=Log[dep[x]];~i;--i) if(f[x][i]^f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } void redfs(int x){ vis[x]=0; for(int i=head[x];i;i=Next[i]) if(vis[to[i]]){ redfs(to[i]); js[x]+=js[to[i]],os[x]+=os[to[i]]; } if(x^1 && js[x]==le && !os[x])++ans; return ; } int main(){ n=read(),m=read(); Log[0]=-1; for(register int i=1;i<=n;++i)Log[i]=Log[i>>1]+1; for(register int i=1,ff,tt;i<=m;++i) ff=read(),tt=read(),add(ff,tt),add(tt,ff); dep[1]=1,dfs(1); for(register int i=1;i<=m;++i) if(!v[i<<1]){ int x=to[i<<1],y=to[(i<<1)^1],z=lca(x,y); if((dep[x]+dep[y]-(dep[z]<<1)+1)&1) ++le,js[z]-=2,++js[x],++js[y]; else os[z]-=2,++os[x],++os[y]; } redfs(1); printf("%d",ans+(le==1)); return 0; }
T3
- 这是贪心么?
- 反正就是同个序列内能匹配就匹配,然后剩下的相互匹配,最后再和没有要求的区域匹配。
- 我觉得难点是把给出的区间分成序列。
- 其实知道结论就很简单了:被相同区间集合覆盖的点在一个序列里。
- 可以对每个点的覆盖区间集合Hash,然后就可以得到同一个序列中的点了。
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define int short #define ll long long #define ull unsigned long long using namespace std; int const N=2001; ull const p=13131; int n,m; char s[N]; int a[N],ans; vector<char>sc[N]; int tot,c[2],cp[2]; struct node{ int id; ull hs; }q[N]; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline int _min(int x,int y){ return x<y?x:y; } inline int _max(int x,int y){ return x>y?x:y; } main(){ scanf("%s",s+1); n=strlen(s+1); m=read(); for(register int i=1;i<=m;++i)a[i]=read()+1; for(register int i=1;i<=m;++i) for(register int j=a[i],lit=read()+1;j<=lit;++j) q[j].hs=q[j].hs*p+i; for(register int i=1;i<=n;++i)q[i].id=i,++c[s[i]==')']; sort(q+1,q+n+1,[](node skyh,node yxs){ return (skyh.hs^yxs.hs)?skyh.hs<yxs.hs:skyh.id<yxs.id; }); for(register int i=1;i<=n;++i) sc[tot=tot+(q[i].hs!=q[i-1].hs)].push_back(s[q[i].id]),++cp[!tot]; if((_min(c[0],c[1])<<1)<cp[0])return puts("-1"),0; for(register int i=1,lc,lm,rc,rm,z,resl=0,resr=0;i<=tot;++i){ if(sc[i].size()&1)return puts("-1"),0; lc=lm=rc=rm=0; for(register auto &j:sc[i]) if(j==')')lm=_max(lm,++lc); else --lc; for(register auto j=sc[i].rbegin();j!=sc[i].rend();++j) if(*j=='(')rm=_max(rm,++rc); else --rc; z=min(lm,rm); ans+=z+1>>1; if(lm==rm)continue; if(rm==z){ lm=lm-z>>1,z=min(lm,resr); lm-=z,resr-=z; ans+=lm,resl+=lm; continue; } rm=rm-z>>1,z=min(rm,resl); rm-=z,resl-=z; ans+=rm,resr+=rm; } printf("%d\n",ans); return 0; }
20191024+
T1
- 退化的数位DP,每一位只有两个状态无需记忆化。
- 时间复杂度$\Theta(log^2N)$,空间复杂度$\Theta(logN)$。
#include<stdio.h> #include<string.h> #define ll long long int const mod=1e9+7; int T,l,r; ll a[31][2]; int s[31]; ll ans; ll dfs(int x){ if(!x)return 1; ll zz=0,z; if(s[x]){ ll lt=1ll<<x-1; zz=lt; a[x][0]=(a[x][0]+lt)%mod; lt>>=1; for(register int i=x-1;i;--i) a[i][1]=(a[i][1]+lt)%mod, a[i][0]=(a[i][0]+lt)%mod; } a[x][s[x]]=(a[x][s[x]]+(z=dfs(x-1)))%mod; z=(z+zz)%mod; return z; } ll Dfs(int x){ if(!x)return 1; ll zz=0,z; if(s[x]){ ll lt=1ll<<x-1; zz=lt; a[x][0]=(a[x][0]-lt)%mod; lt>>=1; for(register int i=x-1;i;--i) a[i][1]=(a[i][1]-lt)%mod, a[i][0]=(a[i][0]-lt)%mod; } a[x][s[x]]=(a[x][s[x]]-(z=Dfs(x-1)))%mod; z=(z+zz)%mod; return z; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%d",&T); while(T--){ scanf("%d%d",&l,&r); memset(a,0,sizeof(a)); ans=0; for(register int i=1;i<=30;++i,r>>=1)s[i]=(r&1); dfs(30); if(l){ --l; for(register int i=1;i<=30;++i,l>>=1)s[i]=(l&1); Dfs(30); } //for(register int i=1;i<=30;++i)printf("%d %lld %lld\n",i,a[i][0],a[i][1]); for(register int i=1;i<=30;++i) a[i][0]=(a[i][0]+mod)%mod,a[i][1]=(a[i][1]+mod)%mod; for(register int i=1,qj=1;i<=30;++i,qj<<=1) ans=(ans+1ll*qj*a[i][0]%mod*a[i][1])%mod; printf("%lld\n",ans*2%mod); } return 0; }
T2
- 暴力应该很好想。
- 然后直接从打表变成刷表,复杂度会降许多。
- 理论下界是$\Omega(N^3)$,然而还是会重复扫描许多状态,所以可能不是很快,但足以通过此题。
#include<cstdio> #define ll long long using namespace std; int const N=300; int T,a,b,c; bool SG[301][301][301],vis[301][301][301]; inline void _swap(int &x,int &y){ int z=x; x=y,y=z; return ; } inline int max(int x,int y){ return x>y?x:y; } int main(){ scanf("%d",&T); for(register int i=0;i<=N;++i) for(register int j=0;j<=N;++j) for(register int k=0;k<=N;++k){ if(vis[i][j][k])continue; SG[i][j][k]=1; for(register int u=i+1;u<=N;++u) vis[u][j][k]=1; for(register int u=j+1;u<=N;++u) vis[i][u][k]=1; for(register int u=k+1;u<=N;++u) vis[i][j][u]=1; for(register int u=1,lit=N-max(i,j);u<=lit;++u) vis[i+u][j+u][k]=1; for(register int u=1,lit=N-max(i,k);u<=lit;++u) vis[i+u][j][k+u]=1; for(register int u=1,lit=N-max(j,k);u<=lit;++u) vis[i][j+u][k+u]=1; for(register int u=1,lit=N-max(i,max(j,k));u<=lit;++u) vis[i+u][j+u][k+u]=1; } while(T--){ scanf("%d%d%d",&a,&b,&c); puts(SG[a][b][c]?"No":"Yes"); } return 0; }
T3
- 不会,颓的码。
#include<stdio.h> #include<string.h> int const N=30003,lar=-0x3f3f3f3f; int n,k,ans=lar; int w[N],wf[N],f[2][N][2],u,v=1; inline int read(){ int ss(0),pp(1);char bb(getchar()); for(;bb<48||bb>57;bb=getchar())if(bb=='-')pp=-1; while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss*pp; } inline int max(int x,int y){ return x>y?x:y; } int main(){ n=read(),k=read()-1; memset(f[0],-0x3f,n+1<<3); for(register int i=1;i<=n;++i)w[i]=w[i-1]+read(); for(register int i=1;i<=n;++i)wf[i]=w[i]<<1; for(register int i=1,mi=0,mx=0;i<=n;++i){ f[0][i][0]=max(f[0][i-1][0],mx-w[i]), f[0][i][1]=max(f[0][i-1][1],w[i]-mi); mi=mi<w[i]?mi:w[i],mx=max(mx,w[i]); } for(register int i=2;i<=k;++i,u=v,v^=1){ int mxu=lar,mxd=lar,mxo=lar,mxl=lar; memset(f[v],-0x3f,n+1<<3); for(register int j=1;j<=n;++j){ f[v][j][0]=max(f[v][j-1][0],max(mxu-wf[j],mxo)), f[v][j][1]=max(f[v][j-1][1],max(mxd+wf[j],mxl)); mxd=max(mxd,f[u][j][0]-wf[j]),mxu=max(mxu,f[u][j][1]+wf[j]); mxo=max(mxo,f[u][j][0]),mxl=max(mxl,f[u][j][1]); } } for(register int i=1,mxu=lar,mxd=lar;i<=n;++i){ ans=max(ans,max(mxu-w[i],mxd+w[i])); mxd=max(mxd,f[u][i][0]-w[i]),mxu=max(mxu,f[u][i][1]+w[i]); } printf("%d",ans); return 0; }
20191025
T1
- 要不是这是出题人的第一套题我绝对会喷S他的……
- 题意是上下移动时必须用机器……而且机器移动并不会无视迷宫限制!
- 然后就是裸的二分+dijkstra了。
- 时间复杂度$\Theta(N^2log(N^2)logK)$,空间复杂度$\Theta(N^2)$。
#include<cstdio> #include<cstring> #define ll long long int const N=105,P=N*N,M=40005; double const eps=1e-4,lar=1e9; int sx,sy,tx,ty,n,m,S,T,lt; int a[N][N],id[N][N]; int head[P],to[M],Next[M],t; double w[M]; int hp[P],tp,pos[P]; double dis[P]; bool vis[P]; double s; inline double min(double x,double y){ return x<y?x:y; } inline void add(int x,int y,double z){ to[++t]=y,w[t]=z; Next[t]=head[x],head[x]=t; return ; } inline void _swap(int &x,int &y){ int z=x; x=y,y=z; return ; } inline void up(int x){ while(x^1){ if(dis[hp[x]]<dis[hp[x>>1]]){ _swap(pos[hp[x]],pos[hp[x>>1]]); _swap(hp[x],hp[x>>1]); x>>=1; } else return ; } } inline void down(int x){ int y=x<<1; while(y<=tp){ if(y^tp && dis[hp[y]]>dis[hp[y|1]])y|=1; if(dis[hp[y]]<dis[hp[x]]){ _swap(pos[hp[x]],pos[hp[y]]); _swap(hp[x],hp[y]); x=y,y<<=1; } else return ; } } inline bool check(double x){ double y=min(1.0,x); t=0; memset(head,0,lt+1<<2); memset(vis,0,lt+1); for(register int i=1;i<=n;++i) for(register int j=1,now;j<=m;++j){ now=id[i][j]; if(!a[i][j-1])add(now,id[i][j-1],1); if(!a[i][j+1])add(now,id[i][j+1],1); if(!a[i-1][j])add(now,id[i-1][j],x); if(!a[i+1][j])add(now,id[i+1][j],x); } for(register int i=1;i<=lt;++i)dis[i]=lar; dis[hp[tp=1]=S]=0; while(tp){ int z=hp[1]; if(z==T)return dis[z]<=s; double dnow=dis[z]; if(dnow>s)return 0; pos[hp[tp]]=1,hp[1]=hp[tp--]; down(1); for(register int i=head[z];i;i=Next[i]) if(dis[to[i]]>dnow+w[i]){ dis[to[i]]=dnow+w[i]; if(!vis[to[i]]){ vis[to[i]]=1; pos[hp[++tp]=to[i]]=tp,up(tp); } else{ int zz=pos[to[i]]; up(zz),down(zz); } } } return 0; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%d%d%d%d%d%d",&n,&m,&sx,&sy,&tx,&ty); for(register int i=1;i<=n;++i) for(register int j=1;j<=m;++j) scanf("%d",&a[i][j]),id[i][j]=(i-1)*n+j; for(register int i=1;i<=n;++i)a[i][0]=a[i][m+1]=1; for(register int i=1;i<=m;++i)a[0][i]=a[n+1][i]=1; scanf("%lf",&s); S=id[sx][sy],T=id[tx][ty],lt=n*m; double l=0,r=s,mid; while(r-l>eps)(check(mid=(l+r)/2)?l:r)=mid; printf("%.3lf",l); return 0; }
T2
- 移动人。利用类似差分的思想可以实现快速转移。
- 设M=max(|r|),时间复杂度$\Theta((N+M)logM)$,空间复杂度$\Theta(N+M)$。
#include<cstdio> #include<algorithm> #include<vector> #define L tr[k].lc #define R tr[k].rc using namespace std; int n,k,mr,ans; struct node{ int w,s; node(int x,int y):w(x),s(y){} }; vector<node>a[500005]; struct S_Tree{ int lc,rc,f,mx; }tr[4000005]; inline int read(){ int ss(0),pp(1);char bb(getchar()); for(;bb<48||bb>57;bb=getchar())if(bb=='-')pp=-1; while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss*pp; } inline int max(int x,int y){ return x>y?x:y; } void build(int x,int y,int k){ L=x,R=y; if(x==y)return ; int mid=x+y>>1; return build(x,mid,k<<1),build(mid+1,y,k<<1|1); } inline void down(int k){ int z=tr[k].f,lk=k<<1; tr[k].f=0; tr[lk].f+=z,tr[lk].mx+=z; tr[lk|1].f+=z,tr[lk|1].mx+=z; return ; } void add(int x,int y,int z,int k){ if(L>=x&&R<=y){tr[k].f+=z;tr[k].mx+=z;return ;} if(tr[k].f)down(k); int mid=L+R>>1,lk=k<<1; if(x<=mid)add(x,y,z,lk); if(y>mid)add(x,y,z,lk|1); tr[k].mx=max(tr[lk].mx,tr[lk|1].mx); return ; } int ask(int x,int k){ if(R<=x)return tr[k].mx; if(tr[k].f)down(k); int mid=L+R>>1; if(x>mid)return max(ask(x,k<<1),ask(x,k<<1|1)); return ask(x,k<<1); } int main(){ n=read(),k=read(); for(register int i=1,ff,tt;i<=n;++i){ ff=read(),tt=read(); if(tt<0)continue; ff=max(ff,0),mr=max(mr,tt); a[ff].push_back(node(ff-1,1)),a[tt+1].push_back(node(ff-1,-1)); } build(-1,mr,1); for(register int i=0,z;i<=mr;++i){ for(register auto &j:a[i])add(-1,j.w,j.s,1); add(i,i,z=ask(max(i-k,-1),1),1),ans=max(ans,z); } printf("%d",ans); return 0; }
T3
- 不是很理解。
#include<cstdio> #include<cstring> #include<map> #define mp make_pair using namespace std; int const N=1e6+5; char a[N],b[N]; int l[N],r[N]; int n,m; long long ans; int f[N][6]; map<pair<char,char>,int>s={{mp('A','B'),0},{mp('A','C'),1},{mp('C','B'),2},{mp('B','C'),3},{mp('C','A'),4},{mp('B','A'),5}}; int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%s%s",a+1,b+1); n=strlen(a+1),m=strlen(b+1); register int i=l[1]=1,ptr=1; for(register int i=1;i<n;){ if(ptr<=n&&a[i]==b[ptr])++ptr; l[++i]=ptr; } ptr=1; for(i=1;i<=n&&ptr<m;++i){ while(ptr<m&&a[i]!=b[ptr])++ptr; r[i]=ptr++; ans+=r[i]-l[i]+1; } for(;i<=n;++i)r[i]=m,ans+=m-l[i]+1; for(register int i=2;i<=m;++i){ for(register int j=0;j<=5;++j)f[i][j]=f[i-1][j]; if(b[i]==b[i-1])continue; int x=s[mp(b[i-1],b[i])]; ++f[i][x]; } for(register int i=2;i<=n;++i){ if(a[i-1]==a[i])continue; int x=s[mp(a[i],a[i-1])]; ans-=f[r[i]][x]-f[l[i]-1][x]; } printf("%lld",ans); return 0; }
20191026
T1
- 暴力很好想到。
- 题目中有一个隐藏的条件,就是身高的不同数值最多只有6000个(140~200cm,两位小数)。
- 所以直接离散化硬干就完了。
- 时间复杂度$\Theta(N^2K)$,空间复杂度$\Theta(NK)$。
#include<cstdio> #include<algorithm> using namespace std; const double lar=1e18; double a[100001],f[6002][22]; double ans=lar; int n,k,m; template<class T> inline T _min(T x,T y){ return x<y?x:y; } constexpr double pf(double x){ return x*x; } int main(){ scanf("%d%d",&n,&k); for(register int i=1;i<=n;++i)scanf("%lf",&a[i]); sort(a+1,a+n+1); for(register int i=1;i<=n;++i) if(a[i]!=a[i-1])a[++m]=a[i]; for(register int i=1;i<=k;++i)f[0][i]=lar; k=min<int>(m,k); for(register int i=1;i<=m;++i){ f[i][0]=lar; for(register int j=1;j<=k;++j){ f[i][j]=lar; for(register int u=1;u<=i;++u) f[i][j]=_min<double>(f[i][j],f[u-1][j-1]+pf(a[i]-a[u])); } } printf("%.2lf",f[m][k]); return 0; }
T2
- 大模拟。不过没那么麻烦吧……破千行的有点过分。
- 不过我考试打了3个小时也没打完……
- 我把四个数压成了一个状态了,压缩方法是将${a,b,c,d}$压成$9^3\times a+9^2\times b+9^3\times c +d$。
- 注意一些边界就行了。
#include<cstdio> using namespace std; int const F=9,S=81,T=729,lt=8*(1+F+S+T); double const gp=1.0/3.0; int t[20][20]; double as[20][20]; double a[lt<<2],g[10][20],gj[10][20]; int vis[lt<<2],fp[lt<<2][5]; int m,qj[100]; int mp[300]; //1:Might 2:Speed 3:Sanity 4:Knowledge inline int min(int x,int y){ return x<y?x:y; } inline int max(int x,int y){ return x>y?x:y; } inline int mk(int x){ return fp[x][1]+fp[x][2]*F+fp[x][3]*S+fp[x][4]*T; } inline void add(int x,int y,int z){ if(!z)return ; if(y){ for(register int i=lt;i;--i){ if(vis[i] || !a[i]||fp[i][x]==8)continue; int zz=fp[i][x]; fp[i][x]=min(8,fp[i][x]+z); a[mk(i)]+=a[i],a[i]=0; fp[i][x]=zz; } return ; } for(register int i=1;i<=lt;++i){ if(vis[i] || !a[i])continue; int zz=fp[i][x]; fp[i][x]=max(0,fp[i][x]-z); a[mk(i)]+=a[i],a[i]=0; fp[i][x]=zz; } return ; } inline void change(int x,int y,int u){ if(!u)return ; if(y){ for(register int i=lt;i;--i){ if(vis[i]||!a[i]||fp[i][x]==8)continue; int z=fp[i][x]; for(register int j=8;j;--j){ fp[i][x]=min(8,fp[i][x]+j); a[mk(i)]+=a[i]*g[u][j],fp[i][x]=z; } a[i]=a[i]*g[u][0]; } return ; } for(register int i=1;i<=lt;++i){ if(vis[i]||!a[i])continue; int z=fp[i][x]; for(register int j=8;j;--j){ fp[i][x]=max(0,fp[i][x]-j); a[mk(i)]+=a[i]*g[u][j],fp[i][x]=z; } a[i]=a[i]*g[u][0]; } return ; } inline void modify(int x,int y,int lto,int ltf,int ltt,int lts){ if(!ltt)return ; if(lts){ for(register int i=lt;i;--i){ if(vis[i]||!a[i]||fp[i][y]==8)continue; int z=t[x][fp[i][x]]; double gnow; switch(ltf){ case 0:gnow=gj[z][16]-gj[z][lto];break; case 1:gnow=gj[z][16]-(lto?gj[z][lto-1]:0);break; case 2:gnow=(lto?gj[z][lto-1]:0);break; case 3:gnow=gj[z][lto];break; } if(!gnow)continue; z=fp[i][y]; for(register int j=8;j;--j){ fp[i][y]=min(8,fp[i][y]+j); a[mk(i)]+=a[i]*g[ltt][j]*gnow,fp[i][y]=z; } a[i]=a[i]*g[ltt][0]*gnow+a[i]*(1-gnow); } return ; } for(register int i=1;i<=lt;++i){ if(vis[i]||!a[i])continue; int z=t[x][fp[i][x]]; double gnow; switch(ltf){ case 0:gnow=gj[z][16]-gj[z][lto];break; case 1:gnow=gj[z][16]-(lto?gj[z][lto-1]:0);break; case 2:gnow=(lto?gj[z][lto-1]:0);break; case 3:gnow=gj[z][lto];break; } if(!gnow)continue; z=fp[i][y]; for(register int j=8;j;--j){ fp[i][y]=max(0,fp[i][y]-j); a[mk(i)]+=a[i]*g[ltt][j]*gnow,fp[i][y]=z; } a[i]=a[i]*g[ltt][0]*gnow+a[i]*(1-gnow); } return ; } //0:> 1:>= 2:< 3:<= inline void update(int x,int y,int lto,int ltf,int ltt,int lts){ if(!ltt)return ; if(lts){ for(register int i=lt;i;--i){ if(vis[i]||!a[i]||fp[i][y]==8)continue; int z=t[x][fp[i][x]]; double gnow; switch(ltf){ case 0:gnow=gj[z][16]-gj[z][lto];break; case 1:gnow=gj[z][16]-(lto?gj[z][lto-1]:0);break; case 2:gnow=(lto?gj[z][lto-1]:0);break; case 3:gnow=gj[z][lto];break; } if(!gnow)continue; z=fp[i][y]; fp[i][y]=min(8,fp[i][y]+ltt); a[mk(i)]+=a[i]*gnow,fp[i][y]=z; a[i]=a[i]*(1-gnow); } return ; } for(register int i=1;i<=lt;++i){ if(vis[i]||!a[i])continue; int z=t[x][fp[i][x]]; double gnow; switch(ltf){ case 0:gnow=gj[z][16]-gj[z][lto];break; case 1:gnow=gj[z][16]-(lto?gj[z][lto-1]:0);break; case 2:gnow=(lto?gj[z][lto-1]:0);break; case 3:gnow=gj[z][lto];break; } if(!gnow)continue; z=fp[i][y]; fp[i][y]=max(0,fp[i][y]-ltt); a[mk(i)]+=a[i]*gnow,fp[i][y]=z; a[i]=a[i]*(1-gnow); } return ; } int main(){ //freopen("1.in","r",stdin); //freopen("2.out","w",stdout); vis[0]=1; for(register int i=lt,z;i;--i){ z=i; fp[i][4]=z/T,z-=fp[i][4]*T; fp[i][3]=z/S,z-=fp[i][3]*S; fp[i][2]=z/F,z-=fp[i][2]*F; fp[i][1]=z; if(!fp[i][4]||!fp[i][3]||!fp[i][2]||!fp[i][1])vis[i]=1; } g[0][0]=1; for(register int i=1;i<=8;++i)g[0][i]=0; for(register int i=1;i<=8;++i){ for(register int j=0;j<=16;++j)g[i][j]=g[i-1][j]*gp; for(register int j=0;j<=15;++j)g[i][j+1]+=g[i-1][j]*gp; for(register int j=0;j<=14;++j)g[i][j+2]+=g[i-1][j]*gp; g[i][16]+=g[i-1][15]*gp+g[i-1][16]; gj[i][0]=g[i][0]; for(register int j=1;j<=16;++j)gj[i][j]=gj[i][j-1]+g[i][j]; } for(register int i=1;i<=8;++i) for(register int j=16;j>8;--j) g[i][8]+=g[i][j]; for(register int i=1;i<=4;++i){ char bb=getchar(); while(bb<48||bb>57)bb=getchar(); for(register int j=1;j<=8;++j,bb=getchar()) t[i][j]=bb^48; scanf("%d",&qj[i]); } a[qj[1]+qj[2]*F+qj[3]*S+qj[4]*T]=100; scanf("%d",&m); mp['i']=1,mp['p']=2,mp['a']=3,mp['n']=4; while(m--){ char bb=getchar(); while(bb<'A'||bb>'Z')bb=getchar(); int x=mp[bb=getchar()]; while(bb!='+'&&bb!='-'&&bb!='>'&&bb!='<')bb=getchar(); if(bb=='+'||bb=='-'){ int ss=0,pp=(bb=='+');bb=getchar(); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); if(bb=='?')change(x,pp,ss); else add(x,pp,ss); } else{ int ss=0,pp=((bb=='>')?0:2),y,ssp=0,ppp=0; bb=getchar(); if(bb=='=')++pp; while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); while(bb<'A'||bb>'Z')bb=getchar(); y=mp[bb=getchar()]; while(bb!='+'&&bb!='-')bb=getchar(); ppp=(bb=='+'),bb=getchar(); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ssp=(ssp<<1)+(ssp<<3)+(bb^48),bb=getchar(); if(bb=='?')modify(x,y,ss,pp,ssp,ppp); else update(x,y,ss,pp,ssp,ppp); } } double ans=0; for(register int i=0;i<=lt;++i){ if(!a[i])continue; if(vis[i])ans+=a[i]; else{ as[1][t[1][fp[i][1]]]+=a[i]; as[2][t[2][fp[i][2]]]+=a[i]; as[3][t[3][fp[i][3]]]+=a[i]; as[4][t[4][fp[i][4]]]+=a[i]; } } printf("%.2lf\n",ans); for(register int i=1;i<=4;++i,puts("")) for(register int j=1;j<=8;++j) printf("%.2lf ",as[i][j]); return 0; }
T3
- 想到记忆化搜索后此题不难解决。
- 我们的状态只记录每种数量对应的小球种类和最后放的小球种类的数量即可。
- 搜索过程相当于模拟。
- 本题需要高精度。(我用的int128我没脸)
#include<cstdio> #define ll __int128_t using namespace std; int n; int c[4]; ll f[13][13][13][4]; char sr[100],z[100],zt; int st=-1; inline void write(ll x){ while(z[++zt]=x%10,x/=10); while(sr[++st]=z[zt--]+48,zt); return ; } ll dfs(int x,int y,int z,int k){ if(f[x][y][z][k])return f[x][y][z][k]; ll ans=0; if(x)ans+=(x-(k==2))*dfs(x-1,y,z,1); if(y)ans+=(y-(k==3))*dfs(x+1,y-1,z,2); if(z)ans+=z*dfs(x,y+1,z-1,3); return f[x][y][z][k]=ans; } int main(){ scanf("%d",&n); for(register int i=1,x;i<=n;++i) scanf("%d",&x),++c[x]; f[0][0][0][1]=1; write(dfs(c[1],c[2],c[3],0)); fwrite(sr,1,st+1,stdout); return 0; }
20191026+
T1
- 打表发现最长的最短路也就48,所以大于48的扩展可以剪掉。
- 当然思考后可以得到扩展倍数的最多扩展4次,再多就会不优,这个可以构造出来。
- 所以本题就是裸的最短路了,直接spfa就行。
- 时间复杂度$\Theta(NK)$,K极小。
#include<bits/stdc++.h> using namespace std; #define ll int char flag[1111111],f[1000010]; ll q[11111111]; ll n,ans=0x3f3f3f3f,L=49,head,tail; void spfa(){ memset(f,0x3f,sizeof(f)); head=tail=1; q[head]=1; f[1]=0;f[0]=1; while(head<=tail){ ll x=q[head++]; flag[x]=0; for(register ll i=x+x,c=f[x]+2;i<=1000005&&c<L;i+=x,c++){ if(f[i]>c){ f[i]=c; if(!flag[i]){ q[++tail]=i; flag[i]=1; } } } if(f[x-1]>f[x]+1){ f[x-1]=f[x]+1; if(!flag[x-1]){ q[++tail]=x-1; flag[x-1]=1; } } } } int main(){ spfa(); scanf("%d",&n); printf("%d\n",f[n]); }
T2
- 竟然考杜教筛……瑟瑟发抖。
- 颓完柿子就是板子了,没啥好说的。
#include<cstdio> #include<cmath> #define ll long long using namespace std; int const N=3e7+1,MOD=7e5+1,lar=-1e9; char mu[N]; bool v[N]; int p[N],tot; int w[N]; ll n,ans; int head[MOD],Next[N],t; ll to[N],wc[N]; inline ll ins(ll x,ll y){ to[++t]=x,wc[t]=y; x%=MOD; Next[t]=head[x],head[x]=t; return y; } inline ll find(ll x){ for(register int i=head[x%MOD];i;i=Next[i]) if(to[i]==x)return wc[i]; return lar; } inline void init(){ mu[1]=w[1]=1; for(register int i=2;i<N;++i){ if(!v[i])mu[p[++tot]=i]=-1; w[i]=w[i-1]+mu[i]; for(register int j=1,z=-mu[i];j<=tot&&i*p[j]<N;++j){ v[i*p[j]]=1; if(i%p[j])mu[i*p[j]]=z; else break; } } return ; } ll ask(ll x){ if(x<N)return w[x]; ll z; if((z=find(x))^lar)return z; z=1; for(ll l=2,r;l<=x;l=r+1) r=x/(x/l),z-=(r-l+1)*ask(x/l); return ins(x,z); } int main(){ init(); scanf("%lld",&n); for(register ll l=2,r,z;;l=r+1){ z=n/(l*l); if(!z)return printf("%lld",n+ans),0; r=sqrt(n/z),ans+=z*(ask(r)-ask(l-1)); } }
T3
- 不会。咕咕咕。
20191027
T1
- 暴力模拟。与拓展顺序无关,普通队列即可。
- 小根堆会被卡所以我用的大根堆。
#include<cstdio> #include<queue> #define ll long long #define mp make_pair using namespace std; int const N=502; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } int n,m,r,c,now; int a[N][N],l[N][N]; bool vis[N][N]; const int mx[4]={0,0,1,-1},my[4]={1,-1,0,0}; priority_queue<pair<int,int>>q; inline int _max(int x,int y){ return x>y?x:y; } void bfs(){ while(!q.empty()){ int x=q.top().first,y=q.top().second,now; q.pop(); vis[x][y]=0; now=l[x][y]=_max(_max(l[x-1][y],l[x][y-1]),_max(l[x][y+1],l[x+1][y]))-a[x][y]; for(register int i=0;i<4;++i){ int tx=x+mx[i],ty=y+my[i]; if(vis[tx][ty]||l[tx][ty]+a[tx][ty]>=now)continue; vis[tx][ty]=1,q.push(mp(tx,ty)); } } return ; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); n=read(),m=read(); for(register int i=1;i<=n;++i) for(register int j=1;j<=m;++j) a[i][j]=read(); l[r=read()][c=read()]=now=read(); for(register int i=0,tx,ty;i<4;++i){ tx=r+mx[i],ty=c+my[i]; if(!tx||!ty||tx>n||ty>m||a[tx][ty]>=now)continue; vis[tx][ty]=1,q.push(mp(tx,ty)); } for(register int i=1;i<=n;++i)vis[i][0]=vis[i][m+1]=1; for(register int j=1;j<=m;++j)vis[0][j]=vis[n+1][j]=1; bfs(); printf("%d",l[read()][read()]); return 0; }
T2
- 我的状压方法是将每个长方形的左下顶点设为1,其余点设0。
- 然后就可以简单状压了。
- 考试的时候忘了一个判断结果WA40kuku。
#include<cstdio> #include<vector> #define ll long long using namespace std; int const M=101,N=1<<8,lar=0x3f3f3f3f; int n,m,ans=lar; int a[M],f[M][N]; vector<int>to[M]; pair<int,int>ls[9],rs[9]; int t,p; inline int _min(int x,int y){ return x<y?x:y; } /*inline void see(int x){ int stk[10],tp=0; for(;x;x>>=1)stk[++tp]=(x&1); while(tp)putchar(stk[tp--]+48); putchar(32); }*/ int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%d%d",&n,&m); for(register int i=1;i<=n;++i) for(register int j=1,z;j<=m;++j) scanf("%d",&z),a[i]|=(z<<j-1); int lit=1<<m; for(register int i=1;i<=n;++i){ for(register int j=0;j<lit;++j){ if((a[i]|j)!=a[i])continue; for(register int k=1,x=a[i],y=j,lt=0;k<=m;++k,x>>=1,y>>=1){ if(y&1)lt=1; else if((x&1) && !(y&1) && !lt)goto ac; else if(!(x&1) && !(y&1))lt=0; } to[i].push_back(j),f[i][j]=lar; ac:; } } for(auto &i:to[1])f[1][i]=0; for(register int i=2;i<=n;++i) for(auto &j:to[i-1]){ int la=f[i-1][j],lt=0,t=0; for(register int k=1,x=a[i-1],y=j;k<=m;++k,x>>=1,y>>=1){ if(y&1){ if(lt)ls[t].second=lt; ls[++t].first=lt=k; } else if((x&1) && !(y&1))lt=k; else if(!(x&1) && !(y&1) && lt)ls[t].second=lt,lt=0; } if(lt)ls[t].second=lt; for(auto &k:to[i]){ int now=t;lt=0;p=0; for(register int u=1,x=a[i],y=k;u<=m;++u,x>>=1,y>>=1){ if(y&1){ if(lt)rs[p].second=lt; rs[++p].first=lt=u; } else if((x&1) && !(y&1))lt=u; else if(!(x&1) && !(y&1) && lt)rs[p].second=lt,lt=0; } if(lt)rs[p].second=lt; for(register int e=1,u=1;e<=t;++e){ while(rs[u].first<ls[e].first&&u<=p)++u; if(u>p)break; if(rs[u]==ls[e])--now; } /*printf("%d %d %d %d ",i,t,p,now); see(j),see(k);puts(""); for(register int u=1;u<=t;++u)printf("!%d %d\n",ls[u].first,ls[u].second); puts("qwq"); for(register int u=1;u<=p;++u)printf("?%d %d\n",rs[u].first,rs[u].second); getchar();*/ f[i][k]=_min(f[i][k],la+now); /*printf("%d %d %d\n",i,k,f[i][k]); for(register int u=1;u<=p;++u)printf("?%d %d\n",rs[u].first,rs[u].second);*/ } } for(auto &i:to[n]){ int c=0; for(register int j=i;j;j-=j&-j)++c; ans=_min(ans,f[n][i]+c); } printf("%d",ans); return 0; }
T3
- 将向量按斜率大小离散化。
- 每个长方形区域影响到的向量是一个区间。
- 用线段树维护即可。
#include<cstdio> #include<cmath> #include<algorithm> #define ll long long #define L tr[k].lc #define R tr[k].rc #define LC k<<1 #define RC k<<1|1 using namespace std; int const N=1e5+5,lar=2e9; double const eps=1e-9; typedef pair<int,int> pi; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } int qs,n,tot; struct node{ int xl,yl,xr,yr; }a[N]; double b[N],K[N]; inline int _max(int x,int y){ return x>y?x:y; } inline double _abs(double x){ return x<0?-x:x; } struct Segment_Tree{ struct node{ int lc,rc,ps,mi; }tr[N<<2]; void build(int x,int y,int k){ L=x,R=y,tr[k].mi=lar; if(x==y)return ; int mid=x+y>>1; return build(x,mid,LC),build(mid+1,y,RC); } void add(int x,int y,int w,int p,int k){ if(L>=x&&R<=y){ if(w<=tr[k].mi)tr[k].mi=w,tr[k].ps=p; return ; } int mid=L+R>>1; if(x<=mid)add(x,y,w,p,LC); if(y>mid)add(x,y,w,p,RC); return ; } pi ask(int x,int k){ pi as=make_pair(tr[k].mi,tr[k].ps); if(L==R)return as; pi z=ask(x,k<<1|(x>(L+R>>1))); return as.first==z.first?(as.second>z.second?as:z):(as.first<z.first?as:z); } }T[2]; int main(){ qs=read(); for(register int i=1;i<=qs;++i){ int opt=read(); if(opt==1){ a[i].xl=read(),a[i].yl=read(); a[i].xr=read(),a[i].yr=read(); continue; } a[i].xl=read(),a[i].yl=read(),a[i].xr=-1; if(a[i].xl&&a[i].yl)b[++n]=K[i]=(double)a[i].yl/(double)a[i].xl; } sort(b+1,b+n+1); for(register int i=1;i<=n;++i) if(b[i]!=b[i-1])b[++tot]=b[i]; int mxx=lar,mxy=lar,asx=0,asy=0; T[0].build(1,tot,1),T[1].build(1,tot,1); for(register int i=1;i<=qs;++i){//printf("???%d\n",a[i].xr); if(~a[i].xr){ if(!a[i].xl&&a[i].yl<=mxy)mxy=a[i].yl,asy=i; if(!a[i].yl&&a[i].xl<=mxx)mxx=a[i].xl,asx=i; if(a[i].xl){ int x=lower_bound(b+1,b+tot+1,1.0*a[i].yl/a[i].xl)-b, y=upper_bound(b+1,b+tot+1,1.0*a[i].yr/a[i].xl)-b-1;//printf("%d %d ",x,y); if(x<=y)T[0].add(x,y,a[i].xl,i,1); } int x=lower_bound(b+1,b+tot+1,1.0*a[i].yl/a[i].xr)-b, y=upper_bound(b+1,b+tot+1,1.0*a[i].yl/a[i].xl)-b-1;//printf("%d %d\n",x,y); if(x<=y)T[1].add(x,y,a[i].yl,i,1); continue; } if(!a[i].xl){printf("%d\n",asy);continue;} if(!a[i].yl){printf("%d\n",asx);continue;} int x=lower_bound(b+1,b+tot+1,K[i])-b;//printf("!%d\n",x); pi px=T[0].ask(x,1),py=T[1].ask(x,1);//printf("%d %d %d %d\n",px.first,px.second,py.first,py.second); double z=K[i]*px.first;//printf("%lf\n",z); printf("%d\n",(_abs(z-py.first)<eps)? _max(px.second,py.second):(z<py.first?px.second:py.second)); } return 0; }
20191028
T1
- 可以发现牌堆数量的种类很少。直接用一个set维护后就可以暴力了。
- 复杂度$\Theta(M\sqrt NlogN)$。
#include<cstdio> #include<set> #define ll long long using namespace std; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } int const N=1e5+5; int ct,n,m; int fa[N],siz[N]; int a[N],BIT[N]; set<int>s; int Get(int x){ return fa[x]==x?x:(fa[x]=Get(fa[x])); } inline void add(int x,int y){ while(x<=n)BIT[x]+=y,x+=x&-x; return ; } inline void merge(int x,int y){ x=Get(x),y=Get(y); if(x==y)return ; --ct; int sx=siz[x],sy=siz[y]; if(!--a[sx])s.erase(sx); if(!--a[sy])s.erase(sy); if(!a[sx+sy]++)s.insert(sx+sy); add(sx,-1),add(sy,-1),add(sx+sy,1); if(sx<sy)fa[x]=y,siz[y]+=siz[x]; else fa[y]=x,siz[x]+=siz[y]; return ; } inline int query(int x){ int y=0; while(x)y+=BIT[x],x-=x&-x; return y; } inline int ask(int x,int y){ long long z=0,now=a[x]; if(x>y)z=now*query(x-y); if(x+y<=n)z+=now*(ct-query(x+y-1)); return z; } int main(){ //freopen("cards105.in","r",stdin); //freopen("1.out","w",stdout); ct=n=read(),m=read(); for(register int i=1;i<=n;++i)fa[i]=i,siz[i]=1; a[1]=n,s.insert(1); add(1,n); while(m--){ int opt=read(); if(opt==1){ int x=read(),y=read(); merge(x,y); continue; } int c=read(); if(!c){printf("%lld\n",1ll*ct*(ct-1)>>1);continue;} long long ans=0; for(auto &i:s)ans+=ask(i,c); printf("%lld\n",ans>>1); } return 0; }
T2
- 不会。颓的码。
#include<cstdio> #include<cstdlib> #include<ctime> #include<cstring> #include<algorithm> #define ll long long #define mp make_pair using namespace std; typedef pair<int,int> pi; int const N=505,mod=998244353; ll const inv2=499122177; int n,mx,ct; int c[N]; pi b[N]; int f[N][N],pos[202][N][N],v[N][N]; ll dp[11][N][N]; int ans[N]; inline int down(int x){ return x<mod?x:x-mod; } inline void Memory(int x,int y){ v[x][y]=++ct,f[0][0]=1; for(register int i=1;i<=y;++i) f[0][i]=inv2*f[0][i-1]%mod; for(register int i=1;i<=x;++i){ f[i][0]=inv2*f[i-1][0]%mod,pos[ct][i][i]=(inv2*f[i-1][0]+pos[ct][i][i])%mod; for(register int j=1;j<y;++j) f[i][j]=(inv2*f[i-1][j]+(i==x?1ll:inv2)*f[i][j-1])%mod, pos[ct][i][i+j]=(inv2*f[i-1][j]+pos[ct][i][i+j])%mod; f[i][y]=(f[i-1][y]+(i==x?1ll:inv2)*f[i][y-1])%mod; pos[ct][i][i+y]=down(pos[ct][i][i+y]+f[i-1][y]); } return ; } void MergeSort(int l,int r,int x,int y,int k){ if(x>y)return ; if(l==r){dp[k][x][1]=1;return ;} int mid=l+r>>1,p=x-1,tk=k+1; while(c[p+1]<=mid)++p; MergeSort(l,mid,x,p,tk),MergeSort(mid+1,r,p+1,y,tk); int sl=p-x+1,sr=y-p,len=y-x+1; if(!sl||!sr) for(register int i=x;i<=y;++i) for(register int j=1;j<=len;++j) dp[k][i][j]=dp[tk][i][j]; else{ if(!v[sl][sr]) Memory(sl,sr),Memory(sr,sl); for(register int i=x;i<=y;++i) for(register int j=1;j<=len;++j) dp[k][i][j]=0; int now1=v[sl][sr],now2=v[sr][sl]; for(register int i=x;i<=p;++i) for(register int j=1;j<=sl;++j) for(register int u=1;u<=len;++u) dp[k][i][u]=(dp[k][i][u]+dp[tk][i][j]*pos[now1][j][u])%mod; for(register int i=p+1;i<=y;++i) for(register int j=1;j<=sr;++j) for(register int u=1;u<=len;++u) dp[k][i][u]=(dp[k][i][u]+dp[tk][i][j]*pos[now2][j][u])%mod; } return ; } signed main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%d",&n); for(register int i=1;i<=n;++i) scanf("%d",&b[i].first),b[i].second=i; sort(b+1,b+n+1); for(register int i=0,tot=0,la=1,z;la<=n;++i,tot=0){ while(la<=n && b[la].first==i) c[++tot]=b[la++].second; c[tot+1]=n+1; MergeSort(1,n,1,tot,0); z=lower_bound(b+1,b+n+1,mp(i,0))-b-1; for(register int j=1;j<=tot;++j) for(register ll k=1;k<=tot;++k) ans[c[j]]=(k*dp[0][j][k]+ans[c[j]])%mod; for(register int j=1;j<=tot;++j) ans[c[j]]=down(ans[c[j]]+z); } for(register int i=1;i<=n;++i) printf("%d ",ans[i]); return 0; }
T3
- 打的由$\Theta(N^2)$暴力进化而来的骗分。
- 我程序特别垃圾,加fwrite才过。
#include<cstdio> #define ll long long #define L tr[k].lc #define R tr[k].rc #define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,P,stdin),S==T))?EOF:*S++) using namespace std; int const N=1e6+5,E=28,Q=(1<<27)-1,lar=1e9,P=1<<23|1; int n,k,mx,mi,am,om; int a[N]; char buf[P],*S,*T; char sr[P],zr[20],zt; int st=-1; bool vis[N]; struct Segment_Tree{ int lc,rc,as; }tr[N<<2]; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline int max(int x,int y){ return x>y?x:y; } inline int min(int x,int y){ return x<y?x:y; } void build(int x,int y,int k){ L=x,R=y,tr[k].as=-1; if(x==y)return ; int mid=x+y>>1,lk=k<<1,rk=lk|1; build(x,mid,lk),build(mid+1,y,rk); return ; } void modify(int x,int y,int z,int k){ if(L>=x&&R<=y){tr[k].as=max(z,tr[k].as);return ;} int mid=L+R>>1; if(x<=mid)modify(x,y,z,k<<1); if(y>mid)modify(x,y,z,k<<1|1); return ; } inline void write(int x){ if(~x){ while(zr[++zt]=x%10+48,x/=10); while(sr[++st]=zr[zt--],zt); } else sr[++st]='-',sr[++st]=49; sr[++st]=32; } void dfs(int x,int k){ x=max(x,tr[k].as); if(L==R){write(x);return ;} return dfs(x,k<<1),dfs(x,k<<1|1); } int main(){ //freopen("2.in","r",stdin); //freopen("3.out","w",stdout); n=read(),k=read(); if(!k){for(int i=1;i<=n;++i)printf("%d ",n);return 0;} for(register int i=1;i<=n;++i)a[i]=read(); build(1,n,1); if(n<=30000){ for(register int i=1,lt;i<=n;++i){ lt=i; for(register int j=i,mx=0,mi=lar,am=Q,om=0;j<=n;++j){ mx=max(mx,a[j]),mi=min(mi,a[j]),am&=a[j],om|=a[j]; if(mi+om-mx-am>=k)lt=j; } if(lt>i)modify(i,lt,lt-i+1,1); } } else for(register int i=1,lt;i<=n;++i){ lt=i; for(register int j=i,mx=0,mi=lar,am=Q,om=0,lm=min(n,i+700);j<=lm;++j){ mx=max(mx,a[j]),mi=min(mi,a[j]),am&=a[j],om|=a[j]; if(mi+om-mx-am>=k)lt=j; } if(lt>i)modify(i,lt,lt-i+1,1); } dfs(-1,1); fwrite(sr,1,st+1,stdout); return 0; }
rp++