2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)
A. Arranging Hat
$f[i][j]$表示保证前$i$个数字有序,修改了$j$次时第$i$个数字的最小值。
时间复杂度$O(n^3m)$。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) typedef pair<int,int>pi; char ten='9'+1; int n,m; string name[55]; string dp[55][88]; string dp2[88]; int prej[55][88]; string pe[55][88]; void up(string &x,string &y,int i,int j,int p){ if(x>y){ prej[i][j]=p; x=y; pe[i][j]=y; } } void solve(){ for(int i=0;i<n;i++)cin>>name[i]; for(int i=0;i<=n;i++){ for(int j=0;j<=n+n;j++){ dp[i][j].assign(m,'9'+1); } } dp[0][0].assign(m,'0'); for(int i=0;i<n;i++){ for(int j=0;j<=n+n;j++){ string ss=dp[i][j]; if(ss[0]==ten)continue; for(int k=0;k<=n+n;k++)dp2[k].assign(m,ten); int use=0; string tmp=name[i]; for(int k=0;k<m;k++){ if(tmp[k]>ss[k]){ if(use+j<=n+n){ //up(dp[i+1][use+j],tmp,i+1,use+j,j); dp2[use]=min(dp2[use],tmp); } } if(ss[k]+1<='9'){ string tmp2=tmp; tmp2[k]=ss[k]+1; if(use+j+1<=n+n){ //up(dp[i+1][use+j+1],tmp2,i+1,use+j+1,j); dp2[use+1]=min(dp2[use+1],tmp2); } } if(tmp[k]!=ss[k])use++; tmp[k]=ss[k]; } if(use+j<=n+n){ dp2[use]=min(dp2[use],tmp); //up(dp[i+1][use+j],tmp,i+1,use+j,j); } for(int k=0;k<n+n;k++){ if(dp2[k][0]>'9')continue; //if(i==2&&j==2)printf("k=%d\n",k); int loc=-1; for(int p=0;p<m;p++){ if(dp2[k][p]>ss[p]){loc=p;break;} } if(loc<0)continue; //if(i==0&&k==0)printf("loc=%d\n",loc); if(ss[loc]+1<dp2[k][loc]){ string nxt=dp2[k]; nxt[loc]=ss[loc]+1; dp2[k+1]=min(dp2[k+1],nxt); //up(dp2[k+1],nxt,i+1,k+1,j); } loc++; string nxt=dp2[k]; while(loc<m&&nxt[loc]=='0')loc++; if(loc<m){ nxt[loc]='0'; dp2[k+1]=min(dp2[k+1],nxt); //up(dp[i+1][k+1],nxt,i+1,k+1,j); } } for(int k=0;k+j<=n+n;k++){ up(dp[i+1][k+j],dp2[k],i+1,k+j,j); } } } /* for(int i=0;i<n;i++){ for(int j=0;j<=n+n;j++){ cout<<dp[i][j]<<" "; } cout<<endl; } */ int ans=-1; for(int i=0;i<=n+n;i++){ if(dp[n][i][0]<='9'){ ans=i; break; } } vector<string>res; for(int i=n,j=ans;i;i--){ res.push_back(pe[i][j]); //printf("i=%d j=%d\n",i,j); j=prej[i][j]; } reverse(res.begin(),res.end()); //printf("%d\n",ans); for(int i=0;i<res.size();i++)cout<<res[i]<<endl; } int main () { //scanf ( "%d%d" , &n,&m ) ; cin>>n>>m;solve () ; int a,b,casdasd,d; return 0 ; }
B. British Menu
首先求出SCC,缩点之后对于每个SCC枚举起点爆搜,当搜到其它SCC时换成DP即可。
时间复杂度$O(5!(n+m))$。
#include<cstdio> #include<algorithm> #include<vector> using namespace std; typedef pair<int,int>P; const int N=100010,M=3000010; int n,m,i,j,x,y,g[N],G[N],sg[N],v[M],nxt[M],ed,d[N]; int ans,dp[N],rk[N]; P e[1000010]; bool vis[N]; int h,t,q[N],from[N],cnt,pool[N]; vector<int>son[N]; inline void add(int x,int y){ // printf("add %d %d\n",x,y); v[++ed]=y;nxt[ed]=g[x];g[x]=ed; v[++ed]=x;nxt[ed]=G[y];G[y]=ed; } inline void ADD(int x,int y){ if(x==y)return; //printf("ADD %d %d\n",x,y); d[y]++; v[++ed]=y;nxt[ed]=sg[x];sg[x]=ed; } void dfs(int x){ vis[x]=1; for(int i=g[x];i;i=nxt[i])if(!vis[v[i]])dfs(v[i]); q[++t]=x; } void dfs2(int x,int y){ vis[x]=0; from[x]=y; //pool[++cnt]=x; //rk[x]=cnt; son[y].push_back(x); for(int i=G[x];i;i=nxt[i])if(vis[v[i]])dfs2(v[i],y); } void dfs3(int x,int y,int S){ // printf("%d %d %d\n",x,y,S); ans=max(ans,y); for(int i=g[x];i;i=nxt[i]){ int u=v[i]; if(from[x]!=from[u])dp[u]=max(dp[u],y+1); else{ if(S>>rk[u]&1)continue; dfs3(u,y+1,S|(1<<rk[u])); } } } inline void deal(int o){//calc SCC o //printf("deal %d\n",o); cnt=0; for(vector<int>::iterator it=son[o].begin();it!=son[o].end();it++){ pool[++cnt]=*it; rk[*it]=cnt; } for(int i=1;i<=cnt;i++){ dfs3(pool[i],dp[pool[i]],1<<i); } } int main(){ scanf("%d%d",&n,&m); for(i=1;i<=m;i++){ scanf("%d%d",&x,&y); e[i]=P(x,y); } sort(e+1,e+m+1); for(i=1;i<=m;i++)if(e[i]!=e[i-1])add(e[i].first,e[i].second); for(i=1;i<=n;i++)if(!vis[i])dfs(i); for(i=n;i;i--)if(vis[q[i]]){ //cnt=0; dfs2(q[i],q[i]); //for(j=1;j<=cnt;j++)dfs3(pool[j],) } for(i=1;i<=n;i++)for(j=g[i];j;j=nxt[j])ADD(from[i],from[v[j]]); for(h=1,t=0,i=1;i<=n;i++)if(from[i]==i&&!d[i]){ q[++t]=i; // printf("start %d\n",i); } while(h<=t)for(i=sg[q[h++]];i;i=nxt[i]){ if(!(--d[v[i]])){ q[++t]=v[i]; // printf("push %d %d\n",q[h-1],v[i]); } } for(i=1;i<=t;i++){ deal(q[i]); } printf("%d",ans+1); }
C. Careful Ascent
推公式。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 100 ; int x , y , n ; void solve () { scanf ( "%d" , &n ) ; double v = 0 , f ; for ( int i = 1 ; i <= n ; ++ i ) { int l , r ; scanf ( "%d%d%lf" , &l , &r , &f ) ; y -= r - l ; v += ( r - l ) * f ; } v += y ; printf ( "%.10f\n" , x / v ) ; } int main () { while ( ~scanf ( "%d%d" , &x , &y ) ) solve () ; return 0 ; }
D. Driving in Optimistan
留坑。
E. Exam Redistribution
从大到小发试卷即可。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) typedef pair<int,int>pi; int n; int a[20000]; void solve () { vector<pi>V; for(int i=1;i<=n;i++)scanf("%d",a+i),V.push_back(pi(a[i],i)); sort(V.begin(),V.end(),greater<pi>()); int sum=0; for(int i=1;i<V.size();i++)sum+=V[i].first; if(sum<V[0].first)puts("impossible"); else{ for(int i=0;i<n;i++)printf("%d%c",V[i].second,i==n-1?'\n':' '); } } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; }
F. Free Weights
二分答案,然后括号匹配即可。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) typedef pair<int,int>pi; const int Maxn=1000020; int n; int a[2][Maxn]; int sta[Maxn]; int top; bool check(int mid){ int cnt=0; for(int i=0;i<2;i++){ top=0; for(int j=1;j<=n;j++){ if(a[i][j]<=mid)continue; if(top&&sta[top]!=a[i][j])return 0; if(top&&sta[top]==a[i][j]){ cnt++; top--; continue; } sta[++top]=a[i][j]; } if(top)return 0; } return 1; } void solve () { for(int it=0;it<2;it++) for(int i=1;i<=n;i++)scanf("%d",&a[it][i]); int l=-1,r=1e9+7; while(l+1<r){ int mid=(l+r)>>1; if(check(mid))r=mid; else l=mid; } printf("%d\n",r); } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
G. Gotta Nudge 'Em All
每条链的答案独立,枚举双倍经验结束的时刻,每次插入新的怪物时,二分那条链上所有怪物进化到了哪一层,树状数组维护判定。
时间复杂度$O(n\log^2n)$。
H. Hamiltonian Hypercube
格雷码转二进制。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 100 ; int n ; int pre[MAXN] , now[MAXN] ; LL get ( int n ) { LL x = 0 ; for ( int i = n - 1 ; i >= 0 ; -- i ) { scanf ( "%1d" , &pre[i] ) ; } now[n - 1] = pre[n - 1] ; for ( int i = n - 2 ; i >= 0 ; -- i ) { now[i] = now[i + 1] ^ pre[i] ; } for ( int i = 0 ; i < n ; ++ i ) if ( now[i]) x += 1LL << i ; return x ; } void solve () { LL x = get ( n ) , y = get ( n ) ; printf ( "%lld\n" , y - x - 1 ) ; } int main () { while ( ~scanf ( "%d" , &n ) ) solve () ; return 0 ; }
I. Iron and Coal
BFS求出起点到每个点、每个点到两种关键点的最短路,然后枚举分界点即可。
#include<cstdio> #include<algorithm> using namespace std; const int N=100010,M=2000010; int n,c0,c1,i,j,x,is0[N],is1[N],g[N],G[N],v[M],nxt[M],ed,ans=M,h,t,q[N]; int A[N],B[N],C[N]; inline void add(int x,int y){ v[++ed]=y;nxt[ed]=g[x];g[x]=ed; v[++ed]=x;nxt[ed]=G[y];G[y]=ed; } int main(){ scanf("%d%d%d",&n,&c0,&c1); while(c0--)scanf("%d",&x),is0[x]=1; while(c1--)scanf("%d",&x),is1[x]=1; for(i=1;i<=n;i++){ scanf("%d",&j); while(j--){ scanf("%d",&x); add(i,x); } } for(i=1;i<=n;i++)A[i]=M; A[q[h=t=1]=1]=0; while(h<=t)for(i=g[x=q[h++]];i;i=nxt[i])if(A[x]+1<A[v[i]])A[q[++t]=v[i]]=A[x]+1; for(i=1;i<=n;i++)B[i]=M; h=1,t=0; for(i=1;i<=n;i++)if(is0[i])B[q[++t]=i]=0; while(h<=t)for(i=G[x=q[h++]];i;i=nxt[i])if(B[x]+1<B[v[i]])B[q[++t]=v[i]]=B[x]+1; for(i=1;i<=n;i++)C[i]=M; h=1,t=0; for(i=1;i<=n;i++)if(is1[i])C[q[++t]=i]=0; while(h<=t)for(i=G[x=q[h++]];i;i=nxt[i])if(C[x]+1<C[v[i]])C[q[++t]=v[i]]=C[x]+1; for(i=1;i<=n;i++)ans=min(ans,A[i]+B[i]+C[i]); if(ans>n)puts("impossible");else printf("%d",ans); }
J. Jupiter Orbiter
网络流。
#include <bits/stdc++.h> using namespace std ; typedef long long LL ; #define clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 3005 ; const int MAXE = 100005 ; const int INF = 0x3f3f3f3f ; struct Edge { int v , c , n ; Edge () {} Edge ( int v , int c , int n ) : v ( v ) , c ( c ) , n ( n ) {} } ; Edge E[MAXE] ; int H[MAXN] , cntE ; int d[MAXN] , cur[MAXN] , pre[MAXN] , gap[MAXN] ; int Q[MAXN] , head , tail ; int s , t , nv , flow ; int n , m , q , cnt ; int idx[35][35][2] ; int qi[MAXN] , ci[MAXN] , cost[MAXN] ; void init () { cntE = 0 ; clr ( H , -1 ) ; } void addedge ( int u , int v , int c ) { E[cntE] = Edge ( v , c , H[u] ) ; H[u] = cntE ++ ; E[cntE] = Edge ( u , 0 , H[v] ) ; H[v] = cntE ++ ; } void rev_bfs () { head = tail = 0 ; clr ( d , -1 ) ; clr ( gap , 0 ) ; gap[0] = 1 ; d[t] = 0 ; Q[tail ++] = t ; while ( head != tail ) { int u = Q[head ++] ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( d[v] == -1 ) { Q[tail ++] = v ; d[v] = d[u] + 1 ; gap[d[v]] ++ ; } } } } int isap () { memcpy ( cur , H , sizeof cur ) ; rev_bfs () ; int u = pre[s] = s , f = flow = 0 , i , mi ; while ( d[s] < nv ) { if ( u == t ) { for ( f = INF , i = s ; i != t ; i = E[cur[i]].v ) { if ( f > E[cur[i]].c ) f = E[cur[u = i]].c ; } for ( i = s ; i != t ; i = E[cur[i]].v ) { E[cur[i]].c -= f ; E[cur[i] ^ 1].c += f ; } flow += f ; } for ( i = cur[u] ; ~i ; i = E[i].n ) { if ( E[i].c && d[u] == d[E[i].v] + 1 ) break ; } if ( ~i ) { cur[u] = i ; pre[E[i].v] = u ; u = E[i].v ; } else { if ( 0 == -- gap[d[u]] ) break ; for ( mi = nv , i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( E[i].c && mi > d[v] ) { cur[u] = i ; mi = d[v] ; } } d[u] = mi + 1 ; gap[d[u]] ++ ; u = pre[u] ; } } return flow ; } void solve () { init () ; for ( int i = 1 ; i <= m ; ++ i ) { scanf ( "%d" , &qi[i] ) ; } for ( int i = 1 ; i <= q ; ++ i ) { scanf ( "%d" , &ci[i] ) ; } s = cnt = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { for ( int j = 1 ; j <= q ; ++ j ) { idx[i][j][0] = ++ cnt ; idx[i][j][1] = ++ cnt ; } } t = cnt + n + 1 ; nv = t + 1 ; LL tot = 0 ; for ( int i = 1 ; i <= n ; ++ i ) { int x , y ; scanf ( "%d" , &x ) ; for ( int j = 1 ; j <= q ; ++ j ) { cost[j] = 0 ; } for ( int j = 1 ; j <= m ; ++ j ) { scanf ( "%d" , &y ) ; cost[qi[j]] += y ; tot += y ; } ++ cnt ; for ( int j = 1 ; j <= q ; ++ j ) { addedge ( s , idx[i][j][0] , cost[j] ) ; addedge ( idx[i][j][0] , idx[i][j][1] , ci[j] ) ; addedge ( idx[i][j][1] , cnt , INF ) ; if ( i < n ) addedge ( idx[i][j][1] , idx[i + 1][j][0] , ci[j] ) ; } addedge ( cnt , t , x ) ; } isap () ; if ( flow != tot ) printf ( "im" ) ; printf ( "possible\n" ) ; } int main () { while ( ~scanf ( "%d%d%d" , &n , &q , &m ) ) solve () ; return 0 ; }
K. Kiwi Trees
由于边长以及角度的限制,每个凸角必能卡住一个圆,然后$O(n^2)$枚举所有可能的圆对即可。
#include<cstdio> #include<algorithm> #include<vector> #include<cmath> using namespace std; const double eps=1e-8; const int N=10000; int sgn(double x){ if(x<-eps)return -1; if(x>eps)return 1; return 0; } struct vec{ double x,y; vec(){x=y=0;} vec(double _x,double _y){x=_x,y=_y;} vec operator+(vec v){return vec(x+v.x,y+v.y);} vec operator-(vec v){return vec(x-v.x,y-v.y);} vec operator*(double v){return vec(x*v,y*v);} vec operator/(double v){return vec(x/v,y/v);} double operator*(vec v){return x*v.x+y*v.y;} double len(){return hypot(x,y);} vec trunc(double l){return (*this)*l/len();} }a[N],q[N]; int n,m,i,j; double cross(vec a,vec b){return a.x*b.y-a.y*b.x;} double dist_point_to_line(vec p,vec a,vec b){ return fabs(cross(p-a,b-a))/(b-a).len(); } double dist_point_to_segment(vec p,vec a,vec b){ if(sgn((p-a)*(b-a))>=0&&sgn((p-b)*(a-b))>=0)return fabs(cross(p-a,b-a))/(b-a).len(); return min((p-a).len(),(p-b).len()); } void solve(vec A,vec B,vec C){ if(cross(A-B,C-B)<0)return; vec D=A-B; D=D/D.len(); D=D+B; vec E=C-B; E=E/E.len(); E=E+B; vec F=(D+E)/2.0; F=F-B; F=F/F.len(); double l=0,r=1e8,mid; while(l+eps<r){ mid=(l+r)/2.0; if(dist_point_to_line(B+(F*mid),A,B)<4000.1)l=mid;else r=mid; } vec o=B+(F*l); for(int i=0;i<n;i++){ if(sgn(dist_point_to_segment(o,a[i],a[i+1])-4000.0)<=0)return; } q[++m]=o; } inline bool check(vec a,vec b){return sgn((a-b).len()-8000.1)>=0;} int main(){ scanf("%d",&n); for(i=0;i<n;i++){ scanf("%lf%lf",&a[i].x,&a[i].y);//mm radius=4000mm a[i+n]=a[i]; } for(i=0;i<n;i++)solve(a[i],a[i+1],a[i+2]); for(i=1;i<=m;i++)for(j=1;j<i;j++)if(check(q[i],q[j])){ printf("%.8f %.8f\n",q[i].x,q[i].y); printf("%.8f %.8f\n",q[j].x,q[j].y); return 0; } puts("impossible"); }