JOI 春合宿 2013 Day2
2時間45分で全完。
取れる問題ちゃんと取れたので良かった
建設事業
平面走査 + segtree + Kruskal + 貪欲
典型盛り合わせみたいな問題で難しいとは感じなかった。
struct edge{ int from,to; ll cost; edge(){} edge(int from,int to,ll cost):from(from),to(to),cost(cost){} bool operator < (const edge& a) const{ return cost < a.cost; } }; struct event{ int x,type; P l,r; // [l,r] event(){} event(int x,P l,P r,int type):x(x),l(l),r(r),type(type){} bool operator < (const event& a) const{ if(x!=a.x)return x < a.x; return type < a.type; } }; const int SIZE = 1<<20; struct segtree{ int seg[SIZE*2],lazy[SIZE*2]; void lazy_evaluate(int k,int l,int r){ seg[k]+=lazy[k]*(r-l); if(k<SIZE-1){ lazy[k*2+1]+=lazy[k]; lazy[k*2+2]+=lazy[k]; } lazy[k]=0; } void update(int a,int b,int k,int l,int r,int x){ lazy_evaluate(k,l,r); if(r<=a||b<=l)return; else if(a<=l&&r<=b){ lazy[k]+=x; lazy_evaluate(k,l,r); }else{ update(a,b,k*2+1,l,(l+r)/2,x); update(a,b,k*2+2,(l+r)/2,r,x); seg[k]=seg[k*2+1]+seg[k*2+2]; } } int query(int a,int b,int k,int l,int r){ lazy_evaluate(k,l,r); if(r<=a||b<=l)return 0; else if(a<=l&&r<=b){ return seg[k]; }else{ int lch = query(a,b,k*2+1,l,(l+r)/2); int rch = query(a,b,k*2+2,(l+r)/2,r); seg[k]=seg[k*2+1]+seg[k*2+2]; return lch+rch; } } void update(int a,int b,int x){ update(a,b,0,0,SIZE,x); } int query(int a,int b){ return query(a,b,0,0,SIZE); } }; struct UnionFind{ int par[SIZE],rank[SIZE]; void init(){ for(int i=0;i<SIZE;i++){ par[i]=i; rank[i]=0; } } int find(int x){ if(par[x]==x)return x; else return par[x]=find(par[x]); } void unite(int a,int b){ a = find(a); b = find(b); if(a==b)return; if(rank[a]<rank[b])par[a]=b; else{ par[b]=a; if(rank[a]==rank[b])rank[a]++; } } bool same(int a,int b){ return find(a)==find(b); } }; int N,M,C; int X[200100],Y[200100],H[500100]; int p[200100],q[200100],r[200100],s[200100]; ll B[500100]; vector<P> fx[600100],fy[600100]; vector<int> zx,zy; vector<ll> uc; vector<edge> es; vector<event> evx,evy; segtree seg; UnionFind uf; int main(){ scanf("%d %d %d",&N,&M,&C); for(int i=0;i<N;i++){ scanf("%d %d",&X[i],&Y[i]); zx.pb(X[i]); zy.pb(Y[i]); } for(int i=0;i<M;i++){ scanf("%d %d %d %d",&p[i],&q[i],&r[i],&s[i]); zx.pb(p[i]);zx.pb(r[i]); zy.pb(q[i]);zy.pb(s[i]); } for(int i=0;i<C;i++){ scanf("%lld %d",&B[i],&H[i]); } sort(all(zx)); sort(all(zy)); zx.erase(unique(all(zx)),zx.end()); zy.erase(unique(all(zy)),zy.end()); for(int i=0;i<N;i++){ X[i] = lower_bound(all(zx),X[i])-zx.begin(); Y[i] = lower_bound(all(zy),Y[i])-zy.begin(); } for(int i=0;i<M;i++){ p[i] = lower_bound(all(zx),p[i])-zx.begin(); q[i] = lower_bound(all(zy),q[i])-zy.begin(); r[i] = lower_bound(all(zx),r[i])-zx.begin(); s[i] = lower_bound(all(zy),s[i])-zy.begin(); } // | ---> for(int i=0;i<N;i++){ fx[X[i]].pb(P(Y[i],i)); } for(int i=0;i<zx.size();i++)sort(all(fx[i])); for(int i=0;i<zx.size();i++){ for(int j=1;j<fx[i].size();j++){ evx.pb(event(i,fx[i][j-1],fx[i][j],1)); } } for(int i=0;i<M;i++){ evx.pb(event(p[i],P(q[i],-1),P(s[i],-1),0)); evx.pb(event(r[i],P(q[i],-1),P(s[i],-1),2)); } sort(all(evx)); for(int i=0;i<evx.size();i++){ event e = evx[i]; //printf("%d %d %d %d\n",zx[e.x],zy[e.l.fi],zy[e.r.fi],e.type); if(e.type==0){ seg.update(e.l.fi,e.r.fi+1,1); }else if(e.type==1){ if(seg.query(e.l.fi,e.r.fi+1)==0){ es.pb(edge(e.l.sec,e.r.sec,zy[e.r.fi]-zy[e.l.fi])); } }else{ seg.update(e.l.fi,e.r.fi+1,-1); } } // ----- ^ for(int i=0;i<N;i++){ fy[Y[i]].pb(P(X[i],i)); } for(int i=0;i<zy.size();i++)sort(all(fy[i])); for(int i=0;i<zy.size();i++){ for(int j=1;j<fy[i].size();j++){ evy.pb(event(i,fy[i][j-1],fy[i][j],1)); } } for(int i=0;i<M;i++){ evy.pb(event(q[i],P(p[i],-1),P(r[i],-1),0)); evy.pb(event(s[i],P(p[i],-1),P(r[i],-1),2)); } sort(all(evy)); for(int i=0;i<evy.size();i++){ event e = evy[i]; //printf("%d %d %d %d\n",zy[e.x],zx[e.l.fi],zx[e.r.fi],e.type); if(e.type==0){ seg.update(e.l.fi,e.r.fi+1,1); }else if(e.type==1){ if(seg.query(e.l.fi,e.r.fi+1)==0){ es.pb(edge(e.l.sec,e.r.sec,zx[e.r.fi]-zx[e.l.fi])); } }else{ seg.update(e.l.fi,e.r.fi+1,-1); } } sort(all(es)); ll base = 0ll; uf.init(); for(int i=0;i<es.size();i++){ edge e = es[i]; //printf("%d %d %lld\n",e.from,e.to,e.cost); if(!uf.same(e.from,e.to)){ uf.unite(e.from,e.to); uc.pb(e.cost); base += e.cost; } } int cnt = sz(uc); vector<ll> sum = uc; sum.pb(0ll); for(int i=cnt-1;i>=0;i--)sum[i]+=sum[i+1]; for(int i=0;i<C;i++){ if(N-cnt>H[i]){ printf("-1\n"); }else{ ll ans = base+(N-cnt)*B[i]; int k = upper_bound(all(uc),B[i])-uc.begin(); int chg = min(H[i]-(N-cnt),cnt-k); ans += B[i]*(ll)chg-sum[cnt-chg]; printf("%lld\n",ans); } } return 0; }
マスコットの片付け
上下、左右を同時に扱ってDPの計算量を落とす。問題読んですぐに解法がわかった。
#define MOD 1000000007 int N,R,C; int ax=INF,ay=INF,bx=-1,by=-1; ll fac[4010]; ll dp[3010][3010]; ll mpow(ll a,ll x){ ll res = 1ll; while(x){ if(x&1)res = (res*a)%MOD; a = (a*a)%MOD; x >>= 1; } return res; } ll fact(int x){ if(x<4000)return fac[x]; ll res = 1; for(int i=1;i<=x;i++)res = (res*(ll)i)%MOD; return res; } ll func(int a,int b){ ll res = fact(a+b); ll inva = mpow(fact(a),MOD-2); ll invb = mpow(fact(b),MOD-2); res = (res*inva%MOD)*invb%MOD; return res; } int main(){ scanf("%d %d",&R,&C); scanf("%d",&N); for(int i=0;i<N;i++){ int x,y; scanf("%d %d",&x,&y); ax = min(ax,x); ay = min(ay,y); bx = max(bx,x); by = max(by,y); } fac[0]=1ll; for(int i=1;i<4000;i++)fac[i]=(fac[i-1]*(ll)i)%MOD; int cx = bx-ax+1,cy = by-ay+1; int f = cx*cy-N; int rx = R-cx,ry = C-cy; dp[0][0]=1ll; for(int i=0;i<=rx;i++){ for(int j=0;j<=ry;j++){ if(i<rx)dp[i+1][j] = (dp[i+1][j]+dp[i][j]*fac[cy+j])%MOD; if(j<ry)dp[i][j+1] = (dp[i][j+1]+dp[i][j]*fac[cx+i])%MOD; } } ll ans = fact(f)*dp[rx][ry]%MOD; ans = ans*func(ax-1,R-bx)%MOD; ans = ans*func(ay-1,C-by)%MOD; printf("%lld\n",ans); return 0; }
スパイ
オイラーツアー + 2次元imos法
vector<int> g[2][2010]; vector<int> euler[2]; int beg[2][2010],end[2][2010]; int root[2]; int k,idx; void dfs(int v){ beg[k][v]=idx++; for(int i=0;i<g[k][v].size();i++){ dfs(g[k][v][i]); } end[k][v]=idx++; } int N,M; int cnt[4010][4010]; void add(int a,int b,int c,int d){ cnt[a][c]++; cnt[a][d]--; cnt[b][c]--; cnt[b][d]++; } int main(){ scanf("%d %d",&N,&M); for(int i=0;i<N;i++){ int p,q; scanf("%d %d",&p,&q); p--;q--; if(p>=0)g[0][p].pb(i); else root[0]=i; if(q>=0)g[1][q].pb(i); else root[1]=i; } for(k=0;k<2;k++){ idx=0; dfs(root[k]); } /*for(int i=0;i<2;i++){ for(int j=0;j<N;j++){ printf("%d %d\n",beg[i][j],end[i][j]); } }*/ for(int i=0;i<M;i++){ int r,s; scanf("%d %d",&r,&s); r--;s--; add(beg[0][r],end[0][r],beg[1][s],end[1][s]); } for(int i=1;i<4010;i++){ for(int j=0;j<4010;j++){ cnt[i][j]+=cnt[i-1][j]; } } for(int j=1;j<4010;j++){ for(int i=0;i<4010;i++){ cnt[i][j]+=cnt[i][j-1]; } } for(int i=0;i<N;i++)printf("%d\n",cnt[beg[0][i]][beg[1][i]]); return 0; }