zoukankan      html  css  js  c++  java
  • 2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest

    A. Toda 2

    按题意模拟即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef pair < int , int > pii ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    const int MAXN = 105 ;
    
    pii a[MAXN] ;
    int G[MAXN * MAXN][MAXN] ;
    int n , x ;
    
    void solve () {
    	int minv = MAXN ;
    	clr ( G , 0 ) ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		scanf ( "%d" , &x ) ;
    		a[i] = pii ( x , i ) ;
    	}
    	int cnt = 0 ;
    	while ( 1 ) {
    		sort ( a + 1 , a + n + 1 ) ;
    		if ( a[1].first == a[n].first ) break ;
    		int m = 0 ;
    		++ cnt ;
    		for ( int i = 1 ; i <= n ; ++ i ) {
    			if ( a[i].first > a[1].first ) ++ m ;
    		}
    		if ( m > 1 && m <= 5 && a[n].first - 1 == a[1].first ) {
    			for ( int i = n - m + 1 ; i <= n ; ++ i ) {
    				a[i].first -- ;
    				G[cnt][a[i].second] = 1 ;
    			}
    			break ;
    		} else {
    			if ( a[n].first ) a[n].first -- ;
    			if ( a[n - 1].first ) a[n - 1].first -- ;
    			G[cnt][a[n].second] = G[cnt][a[n - 1].second] = 1 ;
    		}
    	}
    	printf ( "%d
    " , a[1].first ) ;
    	printf ( "%d
    " , cnt ) ;
    	for ( int i = 1 ; i <= cnt ; ++ i ) {
    		for ( int j = 1 ; j <= n ; ++ j ) {
    			printf ( "%d" , G[i][j] ) ;
    		}
    		puts ( "" ) ;
    	}
    }
    
    int main () {
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    B. Minimum and Maximum

    首先将1和2,3和4,5和6,...两两比较,得到较大值和较小值,再在这$lceilfrac{n}{2} ceil$对中大的比大的,小的比小的即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef pair < int , int > pii ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    const int MAXN = 105 ;
    
    pii a[MAXN] ;
    
    void solve () {
    	int cnt = 0 , n ;
    	scanf ( "%d" , &n ) ;
    	for ( int i = 1 ; i < n ; i += 2 ) {
    		printf ( "? %d %d
    " , i , i + 1 ) ;
    		fflush ( stdout ) ;
    		char op[5] ;
    		scanf ( "%s" , op ) ;
    		if ( op[0] == '<' ) a[++ cnt] = pii ( i , i + 1 ) ;
    		else a[++ cnt] = pii ( i + 1 , i ) ;
    	}
    	if ( n & 1 ) a[++ cnt] = pii ( n , n ) ;
    	for ( int i = 1 ; i < cnt ; ++ i ) {
    		printf ( "? %d %d
    " , a[i].first , a[i + 1].first ) ;
    		fflush ( stdout ) ;
    		char op[5] ;
    		scanf ( "%s" , op ) ;
    		if ( op[0] == '<' ) a[i + 1].first = a[i].first ;
    		printf ( "? %d %d
    " , a[i].second , a[i + 1].second ) ;
    		fflush ( stdout ) ;
    		scanf ( "%s" , op ) ;
    		if ( op[0] == '>' ) a[i + 1].second = a[i].second ;
    	}
    	printf ( "! %d %d
    " , a[cnt].first , a[cnt].second ) ;
    	fflush ( stdout ) ;
    }
    
    int main () {
    	int T ;
    	scanf ( "%d" , &T ) ;
    	while ( T -- ) solve () ;
    	return 0 ;
    }
    

      

    C. Bulmart

    首先BFS求出任意两点间的最短路,然后将物品按照单价从小到大排序。

    对于每个询问,二分答案,然后$O(w)$检验即可。

    时间复杂度$O(n(n+m)+qwlog n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=5010;
    int n,m,Q,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
    int q[N],h,t,d[N][N];
    struct P{int c,k,p;}a[N];
    inline bool cmp(const P&a,const P&b){return a.p<b.p;}
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    inline void bfs(int S){
      int i,x;
      for(i=1;i<=n;i++)d[S][i]=-1;
      q[h=t=1]=S;
      d[S][S]=0;
      while(h<=t)for(i=g[x=q[h++]];i;i=nxt[i])if(d[S][v[i]]<0)d[S][q[++t]=v[i]]=d[S][x]+1;
    }
    inline bool check(int S,int R,int M,int dis){
      int t;
      for(int i=1;i<=m;i++)if(d[S][a[i].c]<=dis&&d[S][a[i].c]>=0){
        int t=min(R,a[i].k);
        if(1LL*t*a[i].p>M)return 0;
        R-=t;
        M-=t*a[i].p;
        if(!R)return 1;
      }
      return 0;
    }
    inline int ask(){
      int S,R,M;
      scanf("%d%d%d",&S,&R,&M);
      int l=0,r=n-1,mid,t=-1;
      while(l<=r){
        mid=(l+r)>>1;
        if(check(S,R,M,mid))r=(t=mid)-1;else l=mid+1;
      }
      return t;
    }
    int main(){
      scanf("%d%d",&n,&m);
      while(m--)scanf("%d%d",&x,&y),add(x,y),add(y,x);
      for(i=1;i<=n;i++)bfs(i);
      scanf("%d",&m);
      for(i=1;i<=m;i++)scanf("%d%d%d",&a[i].c,&a[i].k,&a[i].p);
      sort(a+1,a+m+1,cmp);
      scanf("%d",&Q);
      while(Q--)printf("%d
    ",ask());
      return 0;
    }
    

      

    D. Running Over The Bridges

    贪心,当且仅当再不嗑药就过不了桥的时候嗑药。

    时间复杂度$O(n)$。

    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<string.h>
    #include<string>
    #include<vector>
    #include<set>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<assert.h>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int>pi;
    const int LIM=100001;
    const int Maxn=200020;
    int l[Maxn],t[Maxn];
    int n;
    LL r;
    vector<LL>res;
    LL solve(){
    	for(int i=1;i<=n;i++)if(l[i]>t[i])return -1;
    	LL curt=0,rest=0,ret=0;
    	for(int i=1;i<=n;i++){
    		if(rest>=l[i]){
    			rest-=l[i];
    			curt+=l[i];
    			continue;
    		}
    		l[i]-=rest;t[i]-=rest;
    		curt+=rest;
    		rest=0;
    		if(t[i]>=2*l[i]){
    			curt+=2*l[i];
    		}
    		else{
    			LL x=t[i]-l[i];
    			curt+=2*x;
    			LL restl=l[i]-x;
    			LL ned=restl/r;
    			if(restl%r)ned++;
    			ret+=ned;
    			LL tmp=0;
    			//printf("tmp=%lld
    ",tmp);
    			while(res.size()<LIM){
    				res.push_back(curt+tmp);
    				if(tmp+r<restl)tmp+=r;
    				else{
    					break;
    				}
    			}
    			curt+=restl;
    			rest=r-restl%r;
    			if(rest==r)rest=0;
    		}
    	}
    	return ret;
    }
    int main(){
    	while(scanf("%d%lld",&n,&r)!=EOF){
    		res.clear();
    		for(int i=1;i<=n;i++)scanf("%d",l+i);
    		for(int i=1;i<=n;i++)scanf("%d",t+i);
    		LL ans=solve();
    		if(ans<0){
    			puts("-1");
    		}
    		else{
    			printf("%lld
    ",ans);
    			if(!res.size()||res.size()>LIM-1)puts("");
    			else{
    				for(int i=0;i<res.size();i++)
    					printf("%lld%c",res[i],i==res.size()-1?'
    ':' ');
    			}
    		}
    	}
    	return 0;
    }
    

      

    E. Award Ceremony

    枚举两个队伍,看看谁先揭榜对答案贡献更大,即可得到拓扑序,然后模拟即可。

    时间复杂度$O(n^2)$。

    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<string.h>
    #include<string>
    #include<vector>
    #include<set>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<assert.h>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int>pi;
    const int Maxn=300;
    int n;
    int a[Maxn],b[Maxn];
    pi V1[Maxn],V2[Maxn];
    pi rev1[Maxn],rev2[Maxn];
    int deg[Maxn];
    vector<int>res;
    vector<int>G[Maxn];
    int rk[Maxn],nxtrk[Maxn];
    pi cur[Maxn];
    void solve(){
    	res.clear();
    	for(int i=1;i<=n;i++)deg[i]=0;
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<G[i].size();j++)deg[G[i][j]]++;
    	}
    	queue<int>q;
    	for(int i=1;i<=n;i++)if(!deg[i])q.push(i);
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		res.push_back(u);
    		for(int i=0;i<G[u].size();i++){
    			int v=G[u][i];
    			deg[v]--;
    			if(!deg[v])q.push(v);
    		}
    	}
    }
    int check(int u,int v){
    	int ret=0;
    	if(rev1[u]<rev1[v]){
    		if(rev2[u]<rev1[v]){
    			if(rev2[u]<rev2[v]);
    			else ret++;
    		}
    		else{
    			ret++;
    			if(rev2[u]>rev2[v]);
    			else ret++;
    		}
    	}
    	else{
    		if(rev2[u]>rev1[v]){
    			if(rev2[u]>rev2[v]);
    			else ret++;
    		}
    		else{
    			ret++;
    			if(rev2[u]<rev2[v]);
    			else ret++;
    		}
    	}
    	return ret;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d%d",a+i,b+i),b[i]+=a[i];
    	for(int i=1;i<=n;i++)rev1[i]=pi(-a[i],i),rev2[i]=pi(-b[i],i);
    	for(int i=1;i<=n;i++)G[i].clear();
    	for(int i=1;i<=n;i++){
    		for(int j=i+1;j<=n;j++){
    			int t1=check(i,j),t2=check(j,i);
    			if(t1!=t2){
    				if(t1>t2){
    					G[i].push_back(j);
    				}
    				else G[j].push_back(i);
    			}
    		}
    	}
    	solve();
    
    	for(int i=1;i<=n;i++)cur[i]=pi(-a[i],i);
    	
    	sort(cur+1,cur+n+1);
    	for(int i=1;i<=n;i++){
    	//	printf("val=%d sd=%d
    ",cur[i].first,cur[i].second);
    		rk[cur[i].second]=i;
    	}
    	//for(int i=1;i<=n;i++)printf("%d ",rk[i]);puts("");
    	int ans=0;
    	for(int i=0;i<n;i++){
    		int cs=res[i];
    		for(int j=1;j<=n;j++)if(cur[j].second==cs)cur[j].first=-b[cs];
    		sort(cur+1,cur+n+1);
    		for(int j=1;j<=n;j++)nxtrk[cur[j].second]=j;
    		ans+=abs(nxtrk[cs]-rk[cs]);
    		for(int j=1;j<=n;j++)rk[j]=nxtrk[j];
    		//printf("cs=%d ans=%d
    ",cs,ans);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

    F. Ber Patio

    设$dp[i][j]$表示买了前$i$个物品,目前送了$j$张代金券时,最少要花多少钱,$s[i]$表示前$i$个物品的价值总和。

    那么已知$i,j,dp[i][j],s[i]$,当前手上剩余代金券的总量等于$b+j-(s[i]-dp[i][j])$,所以不需要记录代金券总量,枚举要用多少代金券转移即可。

    状态数$O(frac{nsum a}{10})$。

    时间复杂度$O(frac{nsum a}{4})$。

    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<string.h>
    #include<string>
    #include<vector>
    #include<set>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<assert.h>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int>pi;
    const int Maxn=5050,Maxstate=10020,Inf=1e9;
    int n,b;
    int a[Maxn],sum[Maxn];
    int dp[2][10020];
    short pre[Maxn][Maxstate];
    void init(int cs){
    	for(int i=0;i<Maxstate;i++)dp[cs][i]=Inf;
    }
    int main(){
    	scanf("%d%d",&n,&b);
    	for(int i=1;i<=n;i++)scanf("%d",a+i),sum[i]=sum[i-1]+a[i];
    	int cs=0;
    	init(0);init(1);
    	dp[0][0]=0;
    	for(int i=1;i<=n;i++,cs^=1){
    		init(cs^1);
    		for(int j=0;j<Maxstate;j++){
    			if(dp[cs][j]==Inf)continue;
    			int w=dp[cs][j];
    			int total=sum[i-1];
    			int rest=b+j-(total-w);
    			for(int k=0;k<=rest&&k<=a[i]/2;k++){
    				int nw=w+a[i]-k;
    				int nj=j+(a[i]-k)/10;
    				if(dp[cs^1][nj]>nw){
    					dp[cs^1][nj]=nw;
    					pre[i][nj]=a[i]-k;
    				}
    			}
    		}
    	}
    	int ans=Inf,cur=-1;
    	for(int i=0;i<Maxstate;i++)if(dp[cs][i]<ans){cur=i;ans=dp[cs][i];}
    	printf("%d
    ",ans);
    	vector<int>rep;
    	for(int i=n;i>0;i--){
    		rep.push_back(pre[i][cur]);
    		cur=cur-pre[i][cur]/10;
    	}
    	reverse(rep.begin(),rep.end());
    	for(int i=0;i<rep.size();i++)printf("%d%c",a[i+1]-rep[i],i==rep.size()-1?'
    ':' ');
    	return 0;
    }
    

      

    G. Car Repair Shop

    按题意模拟即可。

    时间复杂度$O(n^2log n)$。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef pair < int , int > pii ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    const int MAXN = 10005 ;
    
    
    int n ;
    vector < pii > G ;
    
    void solve () {
    	G.clear () ;
    	G.push_back ( pii ( 1 , 2e9 ) ) ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		sort ( G.begin () , G.end () ) ;
    		int l , r , d , ok = 0 ;
    		scanf ( "%d%d" , &l , &d ) ;
    		r = l + d - 1 ;
    		for ( int j = 0 ; j < G.size () ; ++ j ) {
    			if ( G[j].first <= l && r <= G[j].second ) {
    				ok = 1 ;
    				printf ( "%d %d
    " , l , r ) ;
    				int l1 = G[j].first , r1 = l - 1 ;
    				int l2 = r + 1 , r2 = G[j].second ; 
    				G[j] = pii ( l1 , r1 ) ;
    				if ( l2 <= r2 ) G.push_back ( pii ( l2 , r2 ) ) ;
    				break ;
    			}
    		}
    		if ( ok ) continue ;
    		for ( int j = 0 ; j < G.size () ; ++ j ) {
    			if ( G[j].second - G[j].first + 1 >= d ) {
    				printf ( "%d %d
    " , G[j].first , G[j].first + d - 1 ) ;
    				G[j].first += d ;
    				break ;
    			}
    		}
    	}
    }
    
    int main () {
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    H. Delete Them

    对于每一位,如果要删的串这一位都相同,那么就是这个字符,否则必须是'?',然后检验是否合法即可。

    时间复杂度$O(n^2)$。

    #include<cstdio>
    #include<cstring>
    const int N=200;
    int n,m,L,i,j,len[N],b[N],v[N];char a[N][N],s[N];
    inline bool check(int x){
      if(len[x]!=L)return 0;
      for(int i=0;i<L;i++)if(s[i]!='?'&&s[i]!=a[x][i])return 0;
      return 1;
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;i++){
        scanf("%s",a[i]);
        len[i]=strlen(a[i]);
      }
      for(i=1;i<=m;i++)scanf("%d",&b[i]),v[b[i]]=1;
      for(i=2;i<=m;i++)if(len[b[i]]!=len[b[1]])return puts("No"),0;
      L=len[b[1]];
      for(i=0;i<L;i++){
        s[i]=a[b[1]][i];
        for(j=2;j<=m;j++)if(s[i]!=a[b[j]][i]){s[i]='?';break;}
      }
      for(i=1;i<=n;i++)if(check(i)!=v[i])return puts("No"),0;
      puts("Yes");
      for(i=0;i<L;i++)putchar(s[i]);
      return 0;
    }
    

      

    I. Olympiad in Programming and Sports

    最大费用最大流裸题。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef pair < int , int > pii ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    const int MAXN = 20005 ;
    const int MAXE = 1000005 ;
    const int INF = 0x3f3f3f3f ;
    
    struct Edge {
    	int v , c , w , n ;
    	Edge () {}
    	Edge ( int v , int c , int w , int n ) : v ( v ) , c ( c ) , w ( w ) , n ( n ) {}
    } ;
    
    Edge E[MAXE] ;
    int H[MAXN] , cntE ;
    int d[MAXN] , vis[MAXN] , cur[MAXN] ;
    int Q[MAXN] , head , tail ;
    int s , t ;
    int flow , cost ;
    int n , P , S ;
    vector < int > A , B ;
    
    void init () {
    	cntE = 0 ;
    	clr ( H , -1 ) ;
    }
    
    void addedge ( int u , int v , int c , int w ) {
    	E[cntE] = Edge ( v , c , w , H[u] ) ;
    	H[u] = cntE ++ ;
    	E[cntE] = Edge ( u , 0 , -w , H[v] ) ;
    	H[v] = cntE ++ ;
    }
    
    int spfa () {
    	clr ( d , INF ) ;
    	clr ( vis , 0 ) ;
    	head = tail = 0 ;
    	Q[tail ++] = s ;
    	d[s] = 0 ;
    	cur[s] = -1 ;
    	while ( head != tail ) {
    		int u = Q[head ++] ;
    		if ( head == MAXN ) head = 0 ;
    		vis[u] = 0 ;
    		for ( int i = H[u] ; ~i ; i = E[i].n ) {
    			int v = E[i].v ;
    			if ( E[i].c && d[v] > d[u] + E[i].w ) {
    				d[v] = d[u] + E[i].w ;
    				cur[v] = i ;
    				if ( !vis[v] ) {
    					vis[v] = 1 ;
    					Q[tail ++] = v ;
    					if ( tail == MAXN ) tail = 0 ;
    				}
    			}
    		}
    	}
    	if ( d[t] == INF ) return 0 ;
    	cost += d[t] ;
    	flow ++ ;
    	for ( int i = cur[t] ; ~i ; i = cur[E[i ^ 1].v] ) {
    		E[i].c -- ;
    		E[i ^ 1].c ++ ;
    	}
    	return 1 ;
    }
    
    void solve () {
    	init () ;
    	s = 0 ;
    	t = n + 2 + 1 ;
    	int pt = n + 1 ;
    	int st = n + 2 ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		int x ;
    		scanf ( "%d" , &x ) ;
    		addedge ( s , i , 1 , 0 ) ;
    		addedge ( i , pt , 1 , -x ) ;
    	}
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		int x ;
    		scanf ( "%d" , &x ) ;
    		addedge ( i , st , 1 , -x ) ;
    	}
    	addedge ( pt , t , P , 0 ) ;
    	addedge ( st , t , S , 0 ) ;
    	cost = flow = 0 ;
    	while ( spfa () ) ;
    	printf ( "%d
    " , -cost ) ;
    	A.clear () ;
    	B.clear () ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		for ( int j = H[i] ; ~j ; j = E[j].n ) {
    			int v = E[j].v ;
    			if ( v == s ) continue ;
    			if ( E[j].c == 0 ) {
    				if ( v == pt ) A.push_back ( i ) ;
    				else B.push_back ( i ) ;
    				break ;
    			}
    		}
    	}
    	for ( int i = 0 ; i < A.size () ; ++ i ) {
    		printf ( "%d%c" , A[i] , i < A.size () - 1 ? ' ' : '
    ' ) ;
    	}
    	for ( int i = 0 ; i < B.size () ; ++ i ) {
    		printf ( "%d%c" , B[i] , i < B.size () - 1 ? ' ' : '
    ' ) ;
    	}
    }
    
    int main () {
    	while ( ~scanf ( "%d%d%d" , &n , &P , &S ) ) solve () ;
    	return 0 ;
    }
    

      

    J. Bottles

    $f[i][j][k]$表示考虑了前$i$个瓶子,目前需要保留$j$个瓶子,容量总和减去被占走的为$k$的最小代价,然后DP即可。

    时间复杂度$O(n^4)$。

    #include<cstdio>
    const int N=105,M=20005,K=10000,inf=10000000;
    int n,i,j,k,x,a[N],b[N],f[2][N][M];
    inline void up(int&x,int y){if(x>y)x=y;}
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++)scanf("%d",&a[i]);
      for(i=1;i<=n;i++)scanf("%d",&b[i]),b[i]-=a[i];
      for(i=0;i<2;i++)for(j=0;j<=n;j++)for(k=0;k<M;k++)f[i][j][k]=inf;
      f[0][0][K]=0;
      for(i=x=1;i<=n;i++,x^=1){
        for(j=0;j<=n;j++)for(k=0;k<M;k++)f[x][j][k]=inf;
        for(j=0;j<=n;j++)for(k=0;k<M;k++)if(f[x^1][j][k]<inf){
          if(k+b[i]<M)up(f[x][j+1][k+b[i]],f[x^1][j][k]);
          if(k-a[i]>=0)up(f[x][j][k-a[i]],f[x^1][j][k]+a[i]);
        }
      }
      for(i=0;i<=n;i++){
        int now=inf;
        for(j=K;j<M;j++)if(f[x^1][i][j]<inf)up(now,f[x^1][i][j]);
        if(now<inf)return printf("%d %d",i,now),0;
      }
    }
    

      

    K. Roads Orientation Problem

    留坑。

    L. Expression Queries

    看上去是很难写的模拟+倍增。

    留坑。


    总结:

    • A题poursoul没想清楚就上去写,导致错误2发,浪费了半小时机时,对于水题也应该准备充分。
    • D题_ilovelife读错输出格式,导致产生无效罚时,下次应注意。
  • 相关阅读:
    nodejs dateformat date-utils
    nodejs async
    nodejs dateformat date-utils
    nodejs timer block-timer timer-ease
    linux 修改 ssh 的端口号,启动hg服务
    linux 下添加 路由
    tkprof 命令行工具用法
    通过API删除库存货位
    使用FROM个性化修改标准FORM的LOV
    批量更新 ITEM 物料属性
  • 原文地址:https://www.cnblogs.com/clrs97/p/6009555.html
Copyright © 2011-2022 走看看