丧病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]); }
时间: 2024-10-22 14:26:47