2016-2017 ACM-ICPC Northwestern European Regional Programming Contest (NWERC 2016)

Claris發表於2016-12-04

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");
}

 

相關文章