2017-4-7校内训练
丧病hzwer的ctsc训练赛 My AC:3/4
思路:乱hash,我比较菜,写的丑代码各种WA+TLE,好久才A掉。
#include<cstdio> #include<algorithm> using namespace std; #define ll long long #define MN 200 #define MX 6000000 #define MM 9000001 #define MOD1 890123798112473LL struct map { struct edge{int nx,t;ll x;}e[MX+5]; int h[MM],en; inline int&operator[](ll x) { int p=(x%MM+MM)%MM; for(int i=h[p];i;i=e[i].nx)if(e[i].x==x)return e[i].t; e[++en]=(edge){h[p],0,x};h[p]=en; return e[en].t; } }mp1,mp2; char s[MN+5]; ll f1[MN+5],f2[MN+5]; int main() { int n,m,k,i,ans=0;ll h1,h2; scanf("%d%d%d",&n,&m,&k); while(n--) { scanf("%s",s+1); for(i=m;i;--i)f1[i]=(f1[i+1]*31^(s[i]+23))%MOD1, f2[i]=(f2[i+1]*37^(s[i]+23)); for(i=1,h1=h2=0;i<=m;++i) { ans+=min(mp1[h1*23333^f1[i+1]]++,mp2[h2*23333^f2[i+1]]++); h1=(h1*37+s[i])%MOD1;h2=(h2*31+s[i]); } } printf("%d",ans); }
思路:显然只有相邻的会被选,先把所有相邻线段用链表链起来塞到堆里,每次取出最小的,与他相邻的线段暂时不能选就删掉,如果要在之后再选相邻的这两条,显然不可能只选其中一条而不选中间这条,我们把这三条合并成左+右-中再塞回堆即可。
#include<cstdio> #include<queue> using namespace std; inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 100000 int a[MN+5],l[MN+5],r[MN+5],w[MN+5],u[MN+5]; class cmp{public:bool operator()(int a,int b){return w[a]>w[b];}}; priority_queue<int,vector<int>,cmp> pq; int main() { int n,k,i,x,ans=0; n=read();k=read(); for(i=1;i<=n;++i)a[i]=read(); w[0]=w[n]=1e9; for(i=1;i<n;++i)l[i]=i-1,r[i]=i+1,w[i]=a[i+1]-a[i],pq.push(i); for(i=0;i<k;++i) { do x=pq.top(),pq.pop();while(u[x]); ans+=w[x]; w[x]=w[l[x]]+w[r[x]]-w[x]; u[l[x]]=u[r[x]]=1; l[x]=l[l[x]];r[x]=r[r[x]]; pq.push(r[l[x]]=l[r[x]]=x); } printf("%d",ans); }
思路:枚举s,每个s先跑一遍单源最短路,只考虑最短路上的边(即满足dis[u]+len=dis[v]的边),得到一张拓扑图,在拓扑图上先dp出s到每个点的最短路宽度$\sigma_{st}$;
考虑每个v,$R(v)=\sum \frac{a_{s}a_{t}\sigma_{st}(v)}{\sigma{st}}=\sum \frac{a_{s}a_{t}\sigma_{sv}\sigma_{vt}}{\sigma{st}}=a_{s}\sigma_{sv}\sum\frac{a_{t}\sigma_{vt}}{\sigma_{st}}$,其中t为v在最短路拓扑图中能到的点。
我们令$f(v)=\sum\frac{a_{t}\sigma_{vt}}{\sigma_{st}}$,则有$f(u)=\sum c_{j}(\frac{a_{v}}{\sigma_{sv}}+f(v))$,其中j为u到v的一条最短路边。然后DP下就做完了。
#include<cstdio> #include<cstring> #define MN 1000 #define MM 4000 #define N 1024 #define lb long double struct edge{int nx,t,w;lb c;}e[MM*2+5]; int n,h[MN+5],en,a[MN+5],d[MN+5],q[MN+5],qn,r[MN+5]; lb fk[MN+5],fj[MN+5],ans[MN+5]; inline void ins(int x,int y,int w,lb c) { e[++en]=(edge){h[x],y,w,c};h[x]=en; e[++en]=(edge){h[y],x,w,c};h[y]=en; } struct data{int x,f;}t[N*2+5]; data min(data a,data b){return a.x<b.x?a:b;} void change(int k,int x){for(t[k+=N].x=x;k>>=1;)t[k]=min(t[k<<1],t[k<<1|1]);} void dj(int s) { memset(d,127,sizeof(d)); memset(t,127,sizeof(t)); for(int i=1;i<=n;++i)t[i+N].f=i; for(change(s,d[s]=0);t[1].x<d[0];change(t[1].f,d[0])) for(int i=h[t[1].f];i;i=e[i].nx)if(d[t[1].f]+e[i].w<d[e[i].t]) change(e[i].t,d[e[i].t]=d[t[1].f]+e[i].w); } void pre() { int i,j; memset(r,0,sizeof(r)); for(i=1;i<=n;++i)for(j=h[i];j;j=e[j].nx) if(d[i]+e[j].w==d[e[j].t])++r[e[j].t]; for(i=1,qn=0;i<=n;++i)if(!r[i])q[++qn]=i; for(i=1;i<=qn;++i) { fk[q[i]]=i<2; for(j=h[q[i]];j;j=e[j].nx) { if(d[e[j].t]+e[j].w==d[q[i]])fk[q[i]]+=fk[e[j].t]*e[j].c; if(d[q[i]]+e[j].w==d[e[j].t]&&!--r[e[j].t])q[++qn]=e[j].t; } } } void solve(int s) { int i,j; memset(r,0,sizeof(r)); for(i=1;i<=n;++i)for(j=h[i];j;j=e[j].nx) if(d[i]+e[j].w==d[e[j].t])++r[i]; for(i=1,qn=0;i<=n;++i)if(!r[i])q[++qn]=i; for(i=1;i<=qn;++i) { fj[q[i]]=0; for(j=h[q[i]];j;j=e[j].nx) { if(d[q[i]]+e[j].w==d[e[j].t])fj[q[i]]+=fj[e[j].t]*e[j].c; if(d[e[j].t]+e[j].w==d[q[i]]&&!--r[e[j].t])q[++qn]=e[j].t; } if(q[i]!=s)ans[q[i]]+=a[s]*fk[q[i]]*fj[q[i]]; fj[q[i]]+=a[q[i]]/fk[q[i]]; } } int main() { int m,i,j,x,y,w;double c; scanf("%d%d",&n,&m); for(i=1;i<=n;++i)scanf("%d",&a[i]); while(m--)scanf("%d%d%d%lf",&x,&y,&w,&c),ins(x,y,w,c); for(i=1;i<=n;++i)dj(i),pre(),solve(i); for(i=1;i<=n;++i)printf("%.7lf\n",(double)ans[i]); }
思路:拿hzwer的标程研究了下,貌似题目有个很重要的东西没说,就是每条链的第一只一定同辈(至少hzwer的标程里貌似是这么认为的)……于是我们先用并查集搞出每只羊的辈分,每一辈之间的繁衍关系相互独立,$\left \lfloor 10ln(1+A) \right \rfloor$这个式子太玄学,显然我们只能枚举A(事实上只要枚举$\left \lfloor 10ln(1+A) \right \rfloor$),枚举确定了这个式子的值后,由于K很小而且每一辈独立,我们可以用最小割求出每一辈链上的点的各个改造情况下的最大收益(最基本的文理分科,不会请绕道),然后状压DP,f[i][j][k]表示前i辈,j个相邻的不同,最后一辈链上的点的改造情况为k,最后用满足$\left \lfloor 10ln(1+j) \right \rfloor$等于我们枚举出的值的f[n][j][k]来更新答案,复杂度O(很复杂)。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define ll long long inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 1000 #define MM 10000 #define MV 21000 #define ME 61000 #define S MV+1 #define T MV+2 #define INF 0x7FFFFFFF char s[MN+5]; int n,k,m,p,c[MN+5],l[MN+5],d[MN+5],f[MN+5],xx[MM+5],yy[MM+5],w1[MM+5],w2[MM+5],A[205]; int qv[205][MN+5],qe[205][MM+5]; ll ans,G[55][16],F[55][205][16]; int gf(int k){return f[k]?f[k]=gf(f[k]):k;} namespace MaxFlow { struct edge{int nx,t,w;}e[ME*2+5]; int h[MV+5],en=1,d[MV+5],q[MV+5],qn,c[MV+5]; inline void ins(int x,int y,int w) { e[++en]=(edge){h[x],y,w};h[x]=en; e[++en]=(edge){h[y],x,0};h[y]=en; } bool bfs() { int i,j; memset(d,0,sizeof(d)); for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx) if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1; return d[T]; } int dfs(int x,int r) { if(x==T)return r; int k,u=0; for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[e[i].t]==d[x]+1) { k=dfs(e[i].t,min(e[i].w,r-u)); u+=k;e[i].w-=k;e[i^1].w+=k; if(u==r)return u; } return d[x]=0,u; } ll dinic(){ll res=0;while(bfs())res+=dfs(S,INF);return res;} }; void cal(int ln,int x,int y) { ll res=0;int i,p,cnt=m; using MaxFlow::ins; for(i=1;i<=qv[x][0];++i) { p=qv[x][i]; if(l[p])if(y&(1<<l[p]-1))ins(S,p,INF),res-=c[p];else ins(p,T,INF); else ins(p,T,c[p]); } for(i=1;i<=qe[x][0];++i) { p=qe[x][i]; res+=ln*(w1[p]+w2[p]); ins(S,++cnt,ln*w2[p]); ins(cnt,xx[p],INF);ins(cnt,yy[p],INF); ins(++cnt,T,ln*w1[p]); ins(xx[p],cnt,INF);ins(yy[p],cnt,INF); } G[x][y]=res-MaxFlow::dinic(); using MaxFlow::h; for(i=1;i<=qv[x][0];++i)h[qv[x][i]]=0; for(i=m;++i<=cnt;)h[i]=0; h[S]=h[T]=0;MaxFlow::en=1; } void dp(int ln) { int i,j,l,p,d,df; memset(F,128,sizeof(F)); for(l=0;l<1<<k;++l)F[1][0][l]=G[1][l]; for(i=1;i<n;++i)for(j=0;A[j]<=ln;++j)for(l=0;l<1<<k;++l) if(F[i][j][l]>F[0][0][0])for(p=0;p<1<<k;++p) { for(d=df=0;d<k;++d)if((l&(1<<d))!=(p&(1<<d)))++df; if(A[j+df]<=ln) F[i+1][j+df][p]=max(F[i+1][j+df][p],F[i][j][l]+G[i+1][p]); } for(j=0;A[j]<=ln;++j)if(A[j]==ln)for(l=0;l<1<<k;++l)ans=max(ans,F[n][j][l]); } int main() { int i,j,x;double wd; n=read();k=read();m=read();p=read(); scanf("%s",s+1); for(i=1;i<=m;++i)c[i]=read(); for(i=1;i<=k;++i)for(j=1;j<=n;++j)l[x=read()]=i,d[x]=j; for(i=1;i<=p;++i) xx[i]=read(),yy[i]=read(),w1[i]=read(), scanf("%lf",&wd),w2[i]=int(w1[i]*wd), gf(xx[i])!=gf(yy[i])?f[gf(xx[i])]=gf(yy[i]):0; for(i=1;i<=m;++i)if(d[i])d[gf(i)]=d[i]; for(i=1;i<=m;++i)d[i]=d[gf(i)]?d[gf(i)]:1,qv[d[i]][++qv[d[i]][0]]=i; for(i=1;i<=p;++i)qe[d[xx[i]]][++qe[d[xx[i]]][0]]=i; for(i=0;i<=(n-1)*k;++i)A[i]=int(10*log(i+1));A[i]=INF; for(i=0;i<=(n-1)*k;++i)if(!i||A[i]!=A[i-1]) { for(j=1;j<=n;++j)for(x=0;x<1<<k;++x)cal(A[i],j,x); dp(A[i]); } printf("%lld",ans); }