• 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
    ",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
    ",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
    ",i,j);
    		j=prej[i][j];
    	}
    	reverse(res.begin(),res.end());
    	//printf("%d
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    " , 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?'
    ':' ');
    	}
    }
    
    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
    ",r);
    }
    
    int main () {
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    G. Gotta Nudge 'Em All

    每条链的答案独立,枚举双倍经验结束的时刻,每次插入新的怪物时,二分那条链上所有怪物进化到了哪一层,树状数组维护判定。

    时间复杂度$O(nlog^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
    " , 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
    " ) ;
    }
    
    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
    ",q[i].x,q[i].y);
        printf("%.8f %.8f
    ",q[j].x,q[j].y);
        return 0;
      }
      puts("impossible");
    }
    
  • 相关阅读:
    11g SPA (sql Performance Analyze) 进行升级测试
    SPA游标采集之去除重复
    C++ 实现分数的四则运算
    计算两个数的最大公约数和最小公倍数(欧几里得算法)
    计算a月的第b个星期c
    完数问题
    求整数的最大质因子
    C++ 读取文本文件内容到结构体数组中并排序
    月饼问题PAT B1020(贪心算法)
    路径打印(set以及字符串的相关操作)
  • 原文地址:https://www.cnblogs.com/clrs97/p/6130157.html
Copyright © 2020-2023  润新知