• Asia Hong Kong Regional Contest 2016


    A. Colourful Graph

    可以在$2n$步之内实现交换任意两个点的颜色,然后就可以构造出方案。

    #include <bits/stdc++.h>
    using namespace std ;
    typedef long long LL;
    const int mod=1e9+7,Maxn=222;
    const LL Inf=1LL<<60;
    int n,m,K;
    int col[Maxn],col2[Maxn];
    int done[Maxn],pre[Maxn];
    vector<int>G[Maxn];
    vector<int> way[102][102];//i->j
    int fst[222];
    void bfs(int st){
    	for(int i=1;i<=n;i++)done[i]=i==st?1:0;
    	queue<int>q;
    	q.push(st);
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=0;i<G[u].size();i++){
    			int v=G[u][i];if(done[v])continue;
    			done[v]=1;
    			pre[v]=u;
    			q.push(v);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		int u=i;
    		way[st][i].clear();
    		for(;u!=st;u=pre[u])way[st][i].push_back(u);
    		way[st][i].push_back(st);
    		reverse(way[st][i].begin(),way[st][i].end());
    	}
    }
    void pt(){
    	for(int i=1;i<=n;i++)printf("%d%c",col[i],i==n?'
    ':' ');
    }
    void swp(int st,int ed,int ty){
    	vector<int>tmp=way[st][ed];
    	for(int i=0;i<tmp.size()-1;i++){
    		if(i==tmp.size()-2){
    			if(ty)col[tmp[i+1]]=col[tmp[i]];
    			else swap(col[tmp[i+1]],col[tmp[i]]);
    		}
    		else swap(col[tmp[i]],col[tmp[i+1]]);
    		pt();
    	}
    	for(int i=tmp.size()-2;i>0;i--){
    		swap(col[tmp[i]],col[tmp[i-1]]);
    		pt();
    	}
    }
    void solve () {
    	for(int i=1;i<=n;i++)scanf("%d",col+i),G[i].clear();
    	for(int i=1;i<=n;i++)scanf("%d",col2+i);
    	for(int i=0;i<m;i++){
    		int u,v;scanf("%d%d",&u,&v);
    		G[u].push_back(v);
    		G[v].push_back(u);
    	}
    	//puts("ok");
    	bool flag=1;
    	for(int i=1;i<=n;i++){
    		int t=0;
    		for(int j=1;j<=n;j++)if(col2[i]==col[j]){t=1;break;}
    		if(!t){flag=0;break;}
    	}
    	if(!flag){
    		puts("Impossible");
    		return;
    	}
    	pt();
    	for(int i=1;i<=n;i++)bfs(i);
    	
    	memset(fst,0,sizeof fst);
    	for(int i=1;i<=n;i++){
    		if(!fst[col2[i]]){
    			fst[col2[i]]=i;
    			if(col[i]==col2[i])continue;
    			for(int j=1;j<=n;j++){
    				if(col[j]==col2[i]){
    					swp(j,i,0);
    					break;
    				}
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		if(col[i]!=col2[i])swp(fst[col2[i]],i,1);
    	}
    }
    
    int main () {
    	while ( ~scanf ( "%d%d%d" , &n,&m,&K ) ) solve () ;
    	return 0 ;
    }
    

      

    B. Doors

    答案就是这些折线之间距离的最小值除以2。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    
    double R,L,W,Alpha,Beta;
    int Case;
    
    const double pi=acos(-1.0),eps=1e-9,inf=10000.0;
    
    int sgn(double x){
      if(x<-eps)return -1;
      if(x>eps)return 1;
      return 0;
    }
    struct P{
      double x,y;
      P(){x=y=0;}
      P(double _x,double _y){x=_x,y=_y;}
      P operator+(P v){return P(x+v.x,y+v.y);}
      P operator-(P v){return P(x-v.x,y-v.y);}
      double operator*(P v){return x*v.x+y*v.y;}
      double len(){return hypot(x,y);}
    };
    double cross(P a,P b){return a.x*b.y-a.y*b.x;}
    
    double dist_point_to_segment(P p,P a,P 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());
    }
    
    double cal(P a,P b,P c,P d){
      return min(min(dist_point_to_segment(a,c,d),
                     dist_point_to_segment(b,c,d)),
                 min(dist_point_to_segment(c,a,b),
                     dist_point_to_segment(d,a,b)));
    }
    
    double solve(){
      P A(-inf,W),B(0,W);
      P D(L,W),E(inf,W);
      P G(L,0),H(inf,0);
      Alpha=pi-Alpha,Beta=pi-Beta;
      P C=D+P(cos(Alpha)*L,sin(Alpha)*L);
      P F=G+P(cos(Beta)*L,sin(Beta)*L);
      double ans=min(L,W);
      ans=min(ans,cal(A,B,C,D));
      ans=min(ans,cal(C,D,F,G));
      ans=min(ans,cal(D,E,F,G));
      ans/=2.0;
      ans=min(ans,R);
      ans=max(ans,0.0);
      return ans;
    }
    
    int main(){
      scanf("%lf%lf%lf",&R,&L,&W);
      scanf("%d",&Case);
      while(Case--){
        scanf("%lf%lf",&Alpha,&Beta);
        printf("%.9f
    ",solve());
      }
      return 0;
    }
    

      

    C. Peak Tower

    求出所有线段相交的时刻,在相邻时刻里三分答案即可。时间复杂度$O(n^4log n)$。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=2000;
    const double eps=1e-9;
    double W,H,E,ans=1e9;
    int n,i,j;
    struct Rec{
      double w,h,sx,sy,vx,vy;
      void read(){
        scanf("%lf%lf%lf%lf%lf%lf",&w,&h,&sx,&sy,&vx,&vy);
      }
    }a[N];
    int sgn(double x){
      if(x<-eps)return -1;
      if(x>eps)return 1;
      return 0;
    }
    int m,cnt;
    double vipy[N];
    int cov[N];
    double ct[1000000];
    int cntt;
    struct Ev{
      double x,l,r;int p;
      Ev(){}
      Ev(double _x,double _l,double _r,int _p){x=_x,l=_l,r=_r,p=_p;}
    }e[N];
    inline bool cmp(const Ev&a,const Ev&b){
      return a.x<b.x;
    }
    double cal(double Time){
      //if(Time<-eps||Time>E+eps)return;
      int i,j;
      m=0;
      for(i=1;i<=n;i++){
        double xl=a[i].sx+a[i].vx*Time,
               xr=xl+a[i].w,
               yl=a[i].sy+a[i].vy*Time,
               yr=yl+a[i].h;
        xl=min(max(xl,0.0),W);
        xr=min(max(xr,0.0),W);
        yl=min(max(yl,0.0),H);
        yr=min(max(yr,0.0),H);
        //printf("%.8f %.8f %.8f %.8f
    ",xl,xr,yl,yr);
        if(xl+eps>xr||yl+eps>yr)continue;
        vipy[++m]=yl;
        e[m]=Ev(xl,yl,yr,1);
        vipy[++m]=yr;
        e[m]=Ev(xr,yl,yr,-1);
      }
      double ret=0;
      if(!m){
        //printf("fuck %.8f %.8f
    ",Time,0.0);
        ans=0;
        return 0;
      }
      sort(vipy+1,vipy+m+1);
      sort(e+1,e+m+1,cmp);
      for(i=1;i<m;i++)cov[i]=0;
      for(i=1;i<=m;i++){
        if(i>1){
          for(j=1;j<m;j++){
            if(cov[j]>0)ret+=(vipy[j+1]-vipy[j])*(e[i].x-e[i-1].x);
          }
        }
        if(ret>ans)return ret;
        double l=e[i].l,r=e[i].r;
        //printf("ev %.8f %.8f %.8f %d
    ",e[i].x,l,r,e[i].p);
        for(j=1;j<m;j++){
          double A=vipy[j],B=vipy[j+1];
          if(sgn(A-l)>=0&&sgn(B-r)<=0){
            cov[j]+=e[i].p;
          }
        }
      }
      //printf("%.8f %.8f
    ",Time,ret);
      ans=min(ans,ret);
      return ret;
    }
    inline bool check(double Time){
      if(Time<-eps||Time>E+eps)return 0;
      return 1;
    }
    void deal(double A,double B,double C,double D){
      A-=C;
      B-=D;
      A=-A;
      if(!sgn(B))return;
      if(check(A/B))ct[++cntt]=A/B;
    }
    void search(double l,double r){
      cal(r);
      double m1,m2,s1,s2;
      int step=0;
      while(l+1e-5<r&&step++<10){
        m1=l+(r-l)/3.0;
        m2=r-(r-l)/3.0;
        s1=cal(m1);
        s2=cal(m2);
        if(s1<s2)r=m2-eps;else l=m1+eps;
      }
    }
    int main(){
      scanf("%d%lf%lf%lf",&n,&W,&H,&E);
      for(i=1;i<=n;i++)a[i].read();
      ct[++cntt]=0;
      ct[++cntt]=E;
      a[n+1].w=W;
      a[n+1].h=H;
      for(i=1;i<=n+1;i++)
        for(j=i+1;j<=n+1;j++){
          deal(a[i].sx       ,a[i].vx,a[j].sx       ,a[j].vx);
          deal(a[i].sx+a[i].w,a[i].vx,a[j].sx       ,a[j].vx);
          deal(a[i].sx       ,a[i].vx,a[j].sx+a[j].w,a[j].vx);
          deal(a[i].sx+a[i].w,a[i].vx,a[j].sx+a[j].w,a[j].vx);
          
          deal(a[i].sy       ,a[i].vy,a[j].sy       ,a[j].vy);
          deal(a[i].sy+a[i].h,a[i].vy,a[j].sy       ,a[j].vy);
          deal(a[i].sy       ,a[i].vy,a[j].sy+a[j].h,a[j].vy);
          deal(a[i].sy+a[i].h,a[i].vy,a[j].sy+a[j].h,a[j].vy);
        }
        //cal(5);
      sort(ct+1,ct+cntt+1);
      cal(0);
      for(i=1;i<=cntt;i++)if(ct[i]>ct[i-1]+eps){
        search(ct[i-1],ct[i]);
      }
      printf("%.10f",ans);
    }
    

      

    D. Peak Tram

    每个位置最多$O(n^2)$种可能的高度,然后DP即可。

    #include <bits/stdc++.h>
    using namespace std ;
    typedef long long LL;
    const int mod=1e9+7,Maxn=71;
    const LL Inf=1LL<<60;
    vector<LL>V;
    LL p[Maxn],c[Maxn];
    LL dp[2][142*71][71];
    LL pre[2][142*71][71];
    int getid(LL x){
    	return lower_bound(V.begin(),V.end(),x)-V.begin();
    }
    int n,K;
    int tot;
    void init(int cs){
    	for(int i=0;i<tot;i++){
    		for(int j=0;j<=K;j++)dp[cs][i][j]=Inf;
    	}
    }
    void calpre(int cs){
    	for(int i=0;i<tot;i++){
    		for(int j=0;j<=K;j++){
    			pre[cs][i][j]=dp[cs][i][j];
    			if(i)pre[cs][i][j]=min(pre[cs][i-1][j],pre[cs][i][j]);
    		}
    	}
    }
    inline void up(LL &x,LL y){if(x>y)x=y;}
    void solve () {
    	V.clear();
    	LL tp=0;
    	V.push_back(tp);
    	for(int i=1;i<=n;i++){
    		scanf("%lld%lld",p+i,c+i);
    		for(int j=-n;j<=n;j++)if(p[i]+j>0)V.push_back(p[i]+j);
    	}
    	sort(V.begin(),V.end());
    	V.erase(unique(V.begin(),V.end()),V.end());
    	tot=V.size();
    	int cs=0;
    	init(cs);
    	dp[cs][0][0]=0;
    	calpre(cs);
    	for(int i=1;i<=n;i++){
    		init(cs^1);
    		//bubeikanjian
    		int tid=getid(p[i]);
    		for(int j=1;j<tot;j++){
    			LL cost=0;
    			if(j<tid){
    				cost=abs(V[j]-p[i])*c[i];
    			}
    			for(int k=0;k<=K;k++){
    				up(dp[cs^1][j][k],dp[cs][j][k]+cost);
    			}
    		}
    		//kanjian
    		for(int j=1;j<tot;j++){
    			LL cost=abs(V[j]-p[i])*c[i];
    			for(int k=1;k<=K;k++){
    				up(dp[cs^1][j][k],pre[cs][j-1][k-1]+cost);
    				up(dp[cs^1][j][k],pre[cs][j-1][k]+cost);
    			}
    		}
    		calpre(cs^1);
    		cs^=1;
    	}
    	LL ans=pre[cs][tot-1][K];
    	printf("%lld
    ",ans);
    }
    
    int main () {
    	while ( ~scanf ( "%d%d" , &n,&K ) ) solve () ;
    	return 0 ;
    }
    

      

    E. Perfect k-ary Tree

    换根树形DP,需要记录树的高度,但是因为是满$k$叉树,因此树高是$O(log n)$级别的。

    #include <bits/stdc++.h>
    using namespace std ;
    typedef long long LL;
    const int mod=1e9+7,Maxn=100020;
    int dp1[19][Maxn];
    int n,K;
    vector<int>G[Maxn];
    int f[2][6];
    inline void up(int &x,int y){x+=y;if(x>=mod)x-=mod;}
    void dfs1(int u,int p){
    	for(int i=0;i<G[u].size();i++){
    		int v=G[u][i];if(v==p)continue;
    		dfs1(v,u);
    	}
    	dp1[0][u]=1;
    	//printf("u=%d
    ",u);
    	for(int i=1;(1<<i)<=n;i++){
    		int cs=0;
    		memset(f[cs],0,sizeof f[cs]);
    		f[cs][0]=1;
    		for(int j=0;j<G[u].size();j++){
    			int v=G[u][j];if(v==p)continue;
    			memset(f[cs^1],0,sizeof f[cs^1]);
    			for(int k=0;k<=K;k++){
    				if(!f[cs][k])continue;
    				if(k<K)up(f[cs^1][k+1],1LL*f[cs][k]*dp1[i-1][v]%mod);
    				up(f[cs^1][k],f[cs][k]);
    			}
    			cs^=1;
    		}
    		dp1[i][u]=f[cs][K];
    	}
    	//for(int i=0;(1<<i)<=n;i++)printf("%d ",dp1[i][u]);puts("");
    }
    int dp2[19][Maxn];
    int pre[Maxn][6],suf[Maxn][6];
    int ans;
    void dfs2(int u,int p){
    	for(int h=1;(1<<h)<=n;h++){
    		//suanqianhouzhui
    		memset(pre[0],0,sizeof pre[0]);
    		pre[0][0]=1;
    		for(int i=0;i<G[u].size();i++){
    			int v=G[u][i];if(v==p){memcpy(pre[i+1],pre[i],sizeof pre[i]);continue;}
    			memset(pre[i+1],0,sizeof pre[i+1]);
    			for(int j=0;j<=K;j++){
    				up(pre[i+1][j],pre[i][j]);
    				if(j<K)up(pre[i+1][j+1],1LL*dp1[h-1][v]*pre[i][j]%mod);
    			}
    		}
    		int lst=G[u].size();
    		memset(suf[lst],0,sizeof suf[lst]);
    		suf[lst][1]=dp2[h-1][u];
    		suf[lst][0]=1;
    		for(int i=G[u].size()-1;i>=0;i--){
    			int v=G[u][i];if(v==p){memcpy(suf[i],suf[i+1],sizeof suf[i+1]);continue;}
    			memset(suf[i],0,sizeof suf[i]);
    			for(int j=0;j<=K;j++){
    				up(suf[i][j],suf[i+1][j]);
    				if(j<K)up(suf[i][j+1],1LL*dp1[h-1][v]*suf[i+1][j]%mod);
    			}
    			/*
    			if(h==2&&u==2){
    				printf("v=%d
    ",v);
    				for(int j=0;j<=K;j++)printf("",suf);
    			}
    			*/
    		}
    		/*
    		if(u==2){
    			puts("haha");
    			for(int i=0;i<=G[u].size();i++){
    				for(int j=0;j<=K;j++)printf("%d ",suf[i][j]);puts("");
    			}
    		}
    		*/
    		for(int i=0;i<G[u].size();i++){
    			int v=G[u][i];if(v==p)continue;
    			dp2[h][v]=0;
    			for(int j=0;j<=K;j++){
    				up(dp2[h][v],1LL*pre[i][j]*suf[i+1][K-j]%mod);
    			}
    		}
    		/*
    		if(suf[0][K]){
    			printf("u=%d h=%d suf=%d
    ",u,h,suf[0][K]);
    		}
    		*/
    		up(ans,suf[0][K]);
    	}
    	for(int i=0;i<G[u].size();i++){
    		int v=G[u][i];if(v==p)continue;
    		dp2[0][v]=1;
    		dfs2(v,u);
    	}
    	
    }
    void solve () {
    	for(int i=1;i<=n;i++)G[i].clear();
    	for(int i=1;i<n;i++){
    		int u,v;scanf("%d%d",&u,&v);
    		G[u].push_back(v);
    		G[v].push_back(u);
    	}
    	ans=n;
    	dfs1(1,0);
    	dfs2(1,0);
    	printf("%d
    ",ans);
    }
    
    int main () {
    	while ( ~scanf ( "%d%d" , &n,&K ) ) solve () ;
    	return 0 ;
    }
    

      

    F. Playing with Numbers

    枚举答案中2和3的幂次来自哪里即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 50005 ;
    
    int a[MAXN] , b[MAXN] ;
    int prea[MAXN][2] , preb[MAXN][2] ;
    int sufa[MAXN][2] , sufb[MAXN][2] ;
    int n ;
    
    double getlog ( int x , int y ) {
    	return x * log ( 2.0 ) + y * log ( 3.0 ) ;
    }
    
    void getlcm () {
    	int ansa = 0 , ansb = 0 ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		int tmpa = min ( prea[i - 1][1] , sufa[i + 1][1] ) ;
    		int tmpb = min ( preb[i - 1][1] , sufb[i + 1][1] ) ;
    		tmpa = max ( tmpa , a[i] ) ;
    		tmpb = max ( tmpb , b[i] ) ;
    		if ( getlog ( tmpa , tmpb ) > getlog ( ansa , ansb ) ) {
    			ansa = tmpa ;
    			ansb = tmpb ;
    		}
    	}
    	printf ( "%d %d" , ansa , ansb ) ;
    }
    
    void getgcd () {
    	int ansa = 1000 , ansb = 1000 ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		int tmpa = max ( prea[i - 1][0] , sufa[i + 1][0] ) ;
    		int tmpb = max ( preb[i - 1][0] , sufb[i + 1][0] ) ;
    		tmpa = min ( tmpa , a[i] ) ;
    		tmpb = min ( tmpb , b[i] ) ;
    		if ( getlog ( tmpa , tmpb ) < getlog ( ansa , ansb ) ) {
    			ansa = tmpa ;
    			ansb = tmpb ;
    		}
    	}
    	printf ( "%d %d" , ansa , ansb ) ;
    }
    
    void solve () {
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		scanf ( "%d%d" , &a[i] , &b[i] ) ;
    	}
    	if ( n == 1 ) {
    		printf ( "%d %d %d %d
    " , a[1] , b[1] , a[1] , b[1] ) ;
    		return ;
    	}
    	if ( n == 2 ) {
    		if ( a[1] < a[2] ) swap ( a[1] , a[2] ) ;
    		if ( b[1] < b[2] ) swap ( b[1] , b[2] ) ;
    		printf ( "%d %d %d %d
    " , a[1] , b[1] , a[1] , b[1] ) ;
    		printf ( "%d %d %d %d
    " , a[2] , b[2] , a[2] , b[2] ) ;
    		return ;
    	}
    	prea[0][0] = preb[0][0] = 0 ;
    	prea[0][1] = preb[0][1] = 1000 ;
    	sufa[n + 1][0] = sufb[n + 1][0] = 0 ;
    	sufa[n + 1][1] = sufb[n + 1][1] = 1000 ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		prea[i][0] = max ( prea[i - 1][0] , a[i] ) ;
    		preb[i][0] = max ( preb[i - 1][0] , b[i] ) ;
    		prea[i][1] = min ( prea[i - 1][1] , a[i] ) ;
    		preb[i][1] = min ( preb[i - 1][1] , b[i] ) ;
    	}
    	for ( int i = n ; i >= 1 ; -- i ) {
    		sufa[i][0] = max ( sufa[i + 1][0] , a[i] ) ;
    		sufb[i][0] = max ( sufb[i + 1][0] , b[i] ) ;
    		sufa[i][1] = min ( sufa[i + 1][1] , a[i] ) ;
    		sufb[i][1] = min ( sufb[i + 1][1] , b[i] ) ;
    	}
    	for ( int i = 0 ; i < n ; ++ i ) {
    		if ( i <= n - 3 ) {
    			printf ( "%d %d" , prea[n][0] , preb[n][0] ) ;
    		} else if ( i == n - 2 ) {
    			getlcm () ;
    		} else {
    			printf ( "%d %d" , prea[n][1] , preb[n][1] ) ;
    		}
    		printf ( " " ) ;
    		if ( i == 0 ) {
    			printf ( "%d %d" , prea[n][0] , preb[n][0] ) ;
    		} else if ( i == 1 ) {
    			getgcd () ;
    		} else {
    			printf ( "%d %d" , prea[n][1] , preb[n][1] ) ;
    		}
    		puts ( "" ) ;
    	}
    }
    
    int main () {
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    G. Scaffolding

    留坑。

    H. Slim Cut

    枚举割中最大的边,那么大于它的边都要保留,得到若干个连通块,那么需要把这些连通块划分给$S$或者$T$,使得点数尽量均衡,01背包即可。

    用并查集维护连通块,那么就变成了带增删物品的01背包,在线段树上分治同时用bitset加速即可。

    时间复杂度$O(frac{n^2log n}{64})$。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<bitset>
    using namespace std;
    const int N=50010,M=140000,MAXE=3000000;
    typedef bitset<7010>BS;
    int n,m,i,j,x,y,f[N],size[N],id[N];
    int pos,st[N],en[N],val[N],cnt;
    double ans=1e9;
    int gq[M],g[M],v[MAXE],nxt[MAXE],ed;
    BS base;
    struct E{
      int x,y,w;
    }e[N];
    inline bool cmp(const E&a,const E&b){return a.w>b.w;}
    int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    inline void add(int&x,int y){
      v[++ed]=y;
      nxt[ed]=x;
      x=ed;
    }
    inline void addquery(int x){
      add(gq[pos],x);
    }
    inline void merge(int x,int y){
      x=F(x);
      y=F(y);
      if(x==y)return;
      en[id[x]]=pos;
      en[id[y]]=pos;
      pos++;
      cnt++;
      st[cnt]=pos;
      val[cnt]=size[x]+size[y];
      size[y]+=size[x];
      f[x]=y;
      id[y]=cnt;
    }
    void change(int x,int a,int b,int c,int d,int p){
      if(c<=a&&b<=d){
        add(g[x],p);
        return;
      }
      int mid=(a+b)>>1;
      if(c<=mid)change(x<<1,a,mid,c,d,p);
      if(d>mid)change(x<<1|1,mid+1,b,c,d,p);
    }
    void dfs(int x,int a,int b,BS dp,int cur){
      for(int i=g[x];i;i=nxt[i])dp|=dp<<v[i],cur+=v[i];
      if(a==b){
        if(cur!=n)while(1);
        int now=-1;
        for(int i=n/2;i>=1;i--)if(dp[i]){
          now=i;
          break;
        }
        if(now<1)return;
        for(int i=gq[a];i;i=nxt[i]){
          ans=min(ans,1.0*v[i]/now);
        }
        return;
      }
      int mid=(a+b)>>1;
      dfs(x<<1,a,mid,dp,cur);
      dfs(x<<1|1,mid+1,b,dp,cur);
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++){
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
        e[i].x++;e[i].y++;
      }
      sort(e+1,e+m+1,cmp);
      for(i=1;i<=n;i++){
        f[i]=i;size[i]=1;
        id[i]=++cnt;
        val[i]=1;
        st[i]=1;
      }
      pos=1;
      for(i=1;i<=m;i=j){
        addquery(e[i].w);
        for(j=i;j<=m&&e[i].w==e[j].w;j++){
          merge(e[j].x,e[j].y);
        }
      }
      for(i=1;i<=cnt;i++)if(!en[i])en[i]=pos;
      for(i=1;i<=cnt;i++)change(1,1,pos,st[i],en[i],val[i]);
      base[0]=1;
      dfs(1,1,pos,base,0);
      printf("%.10f",ans);
    }
    

      

    I. Special Tour

    留坑。

    J. Taboo

    建立AC自动机,然后DP即可,发现环就返回无限解。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=200010;
    const int inf=100000000;
    int n,i,j,x;
    char s[N];
    int tot,son[N][2],ban[N],fail[N],q[N];
    int f[N],vis[N],in[N];
    void ins(){
      scanf("%s",s);
      int l=strlen(s);
      int i,x=0,w;
      for(i=0;i<l;i++){
        w=s[i]-'0';
        if(!son[x][w])son[x][w]=++tot;
        x=son[x][w];
      }
      ban[x]=1;
    }
    void make(){
      int h=1,t=0,i,j,x;
      fail[0]=-1;
      for(i=0;i<2;i++)if(son[0][i])q[++t]=son[0][i];
      while(h<=t){
        for(x=q[h++],i=0;i<2;i++)
          if(son[x][i]){
            fail[son[x][i]]=son[fail[x]][i];
            q[++t]=son[x][i];
            ban[son[x][i]]|=ban[fail[son[x][i]]];
          }else{
            son[x][i]=son[fail[x]][i];
          }
      }
    }
    int dp(int x){
      if(in[x]){
        puts("-1");
        exit(0);
      }
      if(vis[x])return f[x];
      in[x]=1;
      vis[x]=1;
      f[x]=-inf;
      if(!ban[x]){
        f[x]=0;
        for(int i=0;i<2;i++){
          f[x]=max(f[x],dp(son[x][i])+1);
        }
      }
      in[x]=0;
     // printf("dp[%d]=%d
    ",x,f[x]);
      return f[x];
    }
    int main(){
      scanf("%d",&n);
      while(n--)ins();
      make();
      dp(0);
      //printf("ans=%d
    ",f[0]);
      for(x=0,i=1;i<=f[0];i++){
        for(int j=0;j<2;j++){
          if(f[son[x][j]]+1==f[x]){
            x=son[x][j];
            printf("%d",j);
            break;
          }
        }
      }
      puts("");
      return 0;
    }
    

      

    K. Team Up

    将包含关系建树,同时将技能按dfs序重标号,那么每门课程都是一个区间。

    考虑贪心,每次取出包含这个点的最小的区间即可。

    用并查集维护每个点向上第一个还可以选人的节点即可。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1500010;
    const int inf=100000000;
    int n,m,p,i,j,x,size[N],g[N],G[N],v[N],nxt[N],ed,a[N],son[N];
    int from[N],father[N];
    int st[N],en[N],dfn;
    int ans;
    int cnt;
    int f[N];
    bool vis[N];
    vector<int>fin[300010];
    inline bool cmp(int x,int y){return size[x]>size[y];}//
    inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;}//
    void dfs(int x){//
      for(int i=son[x];i;i=nxt[i])dfs(v[i]);//
      for(int i=g[x];i;i=nxt[i]){//
       // printf("dfn %d
    ",v[i]);
        if(!vis[v[i]]){
          from[++dfn]=x;//
          vis[v[i]]=1;
        }
      }//
      en[x]=dfn;//
    }//
    int ask(int x){//
      if(!x)return 0;//
      if(f[x]==x){//
        if(G[x])return x;//
        f[x]=father[x];//
      }//
      return f[x]=ask(f[x]);//
    }//
    void solve(){//
      while(1){//
        int now=1;//
        while(1){//
          //printf("->%d %d
    ",now,from[now]);
          x=ask(from[now]);//return a class
          if(!x)return;//
          //if(!G[x])while(1);
          int y=v[G[x]];//
          G[x]=nxt[G[x]];//
          fin[ans+1].push_back(y);//
          now=en[x]+1;//
          if(now>n)break;//
        }
        ans++;
      }
    }
    int main(){
      scanf("%d%d%d",&n,&m,&p);//
      for(i=1;i<=m;i++){//
        scanf("%d",&size[i]);//
        for(j=0;j<size[i];j++){//
          scanf("%d",&x);//
          add(g[i],x);//
        }//
      }//50W
      for(i=1;i<=p;i++){//
        scanf("%d",&x);//
        add(G[x],i);//
      }//30W
      for(i=1;i<=m;i++)a[i]=i;//
      sort(a+1,a+m+1,cmp);//
      for(i=1;i<=m;i++){//
        x=a[i];//
        father[x]=from[v[g[x]]];//
        for(j=g[x];j;j=nxt[j]){//
          from[v[j]]=x;//
        }//
      }//
      for(i=1;i<=n;i++)if(!from[i])return puts("0"),0;//
      for(i=1;i<=m;i++)if(father[i])add(son[father[i]],i);//30W
      for(i=1;i<=m;i++)if(!father[i])dfs(i);//
      //if(dfn<n)while(1);
      for(i=1;i<=m;i++)f[i]=i;//
      //for(i=1;i<=m;i++)printf("%d
    ",father[i]);
      solve();//
      printf("%d
    ",ans);//
      for(i=1;i<=ans;i++){//
        int t=fin[i].size();//
        printf("%d",t);//
        for(int j=0;j<t;j++)printf(" %d",fin[i][j]);//
        puts("");//
      }//
      return 0;//
    }//
    

      

  • 相关阅读:
    H5项目开发分享——用Canvas合成文字
    《JavaScript设计模式 张》整理
    Linux常用指令指南,终端装逼利器
    飞起来的正则表达式
    JavaScript特性(attribute)、属性(property)和样式(style)
    使用 Nginx 提升网站访问速度
    centos 邮件服务 腾讯企业邮箱(免费) 使用iRedmail 需要有公网的centos主机 发邮件协议:smtp 端口25 收邮件协议:pop3 端口110 iredmail安装配置 使用邮箱系统 第三十一节课
    用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面
    mysql字符集调整总结
    因为smb和nfs挂掉导致客户端开机启动不了
  • 原文地址:https://www.cnblogs.com/clrs97/p/6143035.html
Copyright © 2020-2023  润新知