20191013
前言
- 感觉自己稍迷信,但好像loj运势是吉的时候我从来没考好过……
- 然后一天挂两场,比别人少了300分,目测20名+稳了kuku。
- lsc又挂假对拍企图炸我心态,lsc rp--
T1
- 考试打了个$\Theta(N^3)$DP结果还假了,15分滚粗。
- 依靠Yu-shi大神打表找出的规律,我算是水过的这个题吧。
- 时间复杂度$\Theta(N)$,空间复杂度$\Theta(1)$。
- 有时间再考虑证明,先咕着吧。
#include<cstdio> using namespace std; int const N=2002,mod=1e9+7; int n,m; int tp,ans; long long f,iv,ivv; inline long long power(long long x,int y){ long long as=1; for(;y;y>>=1,x=x*x%mod) if(y&1)as=as*x%mod; return as; } inline void read(){ register char bb=getchar(); while(bb^'('&&bb^')')bb=getchar(); for(register int i=1;i<=m;++i,bb=getchar()){ if(bb=='(')++tp; else if(tp)--tp,++ans; } return ; } inline int down(int x){ return x<mod?x:x-mod; } int main(){ scanf("%d%d",&n,&m); if(n&1)return puts("0"),0; if(n==m)return puts("1"),0; read(); int x=n-m+1,y=(n>>1)-m+ans,z=x-y; if(y<z)m=y,y=z,z=m; if(x<y)return puts("0"),0; f=1; for(register int i=1;i<=y;++i)f=f*i%mod; iv=power(f,mod-2); for(register int i=y+1;i<=z;++i)f=f*i%mod; ivv=power(f,mod-2); for(register int i=z+1;i<=x;++i)f=f*i%mod; printf("%lld",f*iv%mod*ivv%mod); return 0; }
T2
- 概率dp。
- 难点在dp含义上。
- f[i][j][k][0/1]表示进行了i次操作,后8位是j,第9位是0/1,从第9位开始连续k位相同的方案数。
- 取后8位可以保证最高位不会有2次进位。
- 转移和答案统计就很简单了。
- 显然f的第一维可以滚动。
- 还有0取反是-1,1和0的互转用!运算。(调了1个小时……)
- 时间复杂度$\Theta(2^8N^2)$,空间复杂度$\Theta(2^8N)$。
#include<cstdio> using namespace std; int const lt=1<<8; double f[2][lt][222][2],ans; int bs[lt],c,n,p; inline int max(int x,int y){ return x>y?x:y; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); scanf("%d%d%d",&c,&n,&p); int sec=c&(lt-1); c>>=8; int thr=0,fur=c&1,lit; while(c){ if((c&1)^fur)break; c>>=1,++thr; } lit=n+(thr=max(thr,1)); f[0][sec][thr][fur]=1; double ff=(double)p/100.0,gg=1.0-ff; register int now=1,cur=0; for(register int i=1;i<=n;++i,now=cur,cur^=1){ for(register int j=0;j<lt;++j) for(register int k=1;k<=lit;++k) f[now][j][k][0]=f[now][j][k][1]=0; for(register int j=0;j<lt;++j) for(register int k=1;k<=lit;++k) for(register int u=0;u^2;++u) if(f[cur][j][k][u]) (((((j<<1)<)>>8)==u)?f[now][(j<<1)&(lt-1)][k+1][u]:f[now][(j<<1)&(lt-1)][1][!u])+=ff*f[cur][j][k][u], (j+1==lt?f[now][0][u?k:1][!u]:f[now][j+1][k][u])+=gg*f[cur][j][k][u]; } for(register int i=0;i<8;++i)bs[1<<i]=i; for(register int i=1;i<lt;++i) for(register int j=1;j<=lit;++j) ans+=(f[cur][i][j][0]+f[cur][i][j][1])*bs[i&-i]; for(register int i=1;i<=lit;++i)ans+=f[cur][0][i][0]*(i+8)+f[cur][0][i][1]*8; printf("%.10lf",ans); return 0; }
T3
- 理解了题意其实不难。
- 如果有奇环那么直接输出-1,可以黑白染色进行判断。
- 否则找出连通图中最短路径最长的点对,将其他点合并。这种构造显然最优。
- 注意图不保证连通,需要把各各连通图的答案累加。
- 本题是稠密图,用vector实现邻接表不不用vector快20倍左右。
- 时空复杂度$\Theta(N)$
#include<cstdio> #include<cstring> #include<vector> using namespace std; int const N=1003,M=2e5+5; int n,m,ans; int t,qs[N],vis[N]; int q[N],dis[N]; bool vs[N]; vector<int>a[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 max(int x,int y){ return x>y?x:y; } bool dfs(int x,int col){ vis[x]=col,qs[++t]=x; for(auto &i:a[x]) if((!vis[i]&&dfs(i,col^1))||vis[i]==col)return 1; return 0; } inline int bfs(int x){ register int u(0),v(1),fr,dnow; memset(vs,1,n+1); vs[q[1]=x]=dis[x]=0; while(u^v){ dnow=dis[fr=q[++u]]+1; for(register auto &i:a[fr]) if(vs[i])vs[i]=0,dis[q[++v]=i]=dnow; } return dis[q[v]]; } int main(){ n=read(),m=read(); while(m--){ int x=read(),y=read(); a[x].push_back(y),a[y].push_back(x); } for(register int i=1;i<=n;++i) if(!vis[i]){ t=0; if(dfs(i,2))return puts("-1"),0; int now=0; for(register int i=1;i<=t;++i) now=max(now,bfs(qs[i])); ans+=now; } printf("%d",ans); return 0; }
rp++