zoukankan      html  css  js  c++  java
  • XVI Open Cup named after E.V. Pankratiev. GP of Siberia

    A. Passage

    枚举两个点,看看删掉之后剩下的图是否是二分图。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 205 ;
    
    vector < int > G[MAXN] ;
    int vis[MAXN] , col[MAXN] ;
    int n ;
    
    int dfs ( int u ) {
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i] ;
    		if ( vis[v] == 0 ) continue ;
    		if ( !col[v] ) {		
    			col[v] = 3 - col[u] ;
    			if ( !dfs ( v ) ) return 0 ;
    		}
    		if ( col[u] + col[v] != 3 ) return 0 ;
    	}
    	return 1 ;
    }
    
    int check () {
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		col[i] = 0 ;
    	}
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		if ( col[i] || !vis[i] ) continue ;
    		col[i] = 1 ;
    		if ( !dfs ( i ) ) return 0 ;
    	}
    	return 1 ;
    }
    
    void solve () {
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		int x , y ;
    		scanf ( "%d" , &x ) ;
    		for ( int j = 0 ; j < x ; ++ j ) {
    			scanf ( "%d" , &y ) ;
    			G[i].push_back ( y ) ;
    			G[y].push_back ( i ) ;
    		}
    		vis[i] = 1 ;
    	}
    	if ( n <= 3 ) {
    		printf ( "Hurrah!
    " ) ;
    		return ;
    	}
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		for ( int j = i + 1 ; j <= n ; ++ j ) {
    			vis[i] = vis[j] = 0 ;
    			if ( check () ) {
    				printf ( "Hurrah!
    " ) ;
    				return ;
    			}
    			vis[i] = vis[j] = 1 ;
    		}
    	}
    	printf ( "Fired.
    " ) ;
    }
    
    int main () {
    	freopen ( "input.txt" , "r" , stdin ) ;
    	freopen ( "output.txt" , "w" , stdout ) ;
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    B. Files list

    按题意模拟。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 10005 ;
    
    map < string , int > mp ;
    map < int , string > mp2 ;
    char s[MAXN] , p[MAXN] ;
    int n ;
    
    void solve () {
    	mp.clear () ;
    	mp2.clear () ;
    	int cnt = 0 ;
    	for ( int i = 0 ; i < n ; ++ i ) {
    		scanf ( "%s" , s ) ;
    		int t = 0 , f = 0 ;
    		for ( int j = 0 ; s[j] ; ++ j ) {
    			if ( f ) p[t ++] = s[j] ;
    			else if ( s[j] == '.' ) f = 1 ;
    		}
    		p[t] = 0 ;
    		if ( mp.count ( p ) ) mp[p] ++ ;
    		else {
    			mp[p] ++ ;
    			mp2[++ cnt] = p ;
    		}
    	}
    	for ( int i = 1 ; i <= cnt ; ++ i ) {
    		cout << mp2[i] << ": " << mp[mp2[i]] << endl ;
    	}
    }
    
    int main () {
    	freopen ( "input.txt" , "r" , stdin ) ;
    	freopen ( "output.txt" , "w" , stdout ) ;
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    C. Graph optimization

    将所有1类限制的边加入,分块bitset判定限制2是否都满足即可。

    时间复杂度$O(frac{nm}{64})$。

    #include<algorithm>
    #include<cstdio>
    #include<bitset>
    #include<set>
    #include<ctime>
    using namespace std;
    typedef bitset<4096>B;
    typedef unsigned long long ll;
    const int N=300010;
    
    int n,m,i,j,k,x,y,z,ans[N][2],quailty;
    int g[N],G[N],v[N],nxt[N],ed;
    
    
    
    int vis[N],q[N],h,t,cnt,f[N],d[N];
    B dp[100010];//dp[x] : this can reach x
    
    set<int>SET[100010];
    
    struct E{int x,y,z;}e[N];
    
    const int BUF=5000000;
    char Buf[BUF],*buf=Buf;
    inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
    
    inline bool cmp(const E&a,const E&b){return a.z<b.z;}
    inline void add(int x,int y){
      v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
    }
    inline void add2(int x,int y){
      v[++ed]=y;nxt[ed]=G[x];G[x]=ed;
    }
    void dfs1(int x){
      vis[x]=1;
      for(int i=g[x];i;i=nxt[i])if(!vis[v[i]])dfs1(v[i]);
      q[++t]=x;
    }
    void dfs2(int x,int y){
      vis[x]=0;f[x]=y;
      for(int i=G[x];i;i=nxt[i])if(vis[v[i]])dfs2(v[i],y);
    }
    inline bool solve(int L,int R){
      if ( clock () > 2.95 * CLOCKS_PER_SEC ) return 1 ;
      int z=e[L].z;
      int i;
      for(i=1;i<=cnt;i++){
        dp[i].reset();
        //if ( clock () > 2.95 * CLOCKS_PER_SEC ) return 1 ;
      }
      for(i=max(z<<12,1);(i>>12)==z;i++){
        dp[f[i]][i&4095]=1;
      }
      for(i=1;i<=cnt;i++){
        int x=q[i];
        for(int j=g[x];j;j=nxt[j]){
          dp[v[j]]|=dp[x];
          //if ( clock () > 2.95 * CLOCKS_PER_SEC ) return 1 ;
        }
      }
      for(i=L;i<=R;i++){
        int x=e[i].x,y=e[i].y;
        //printf("-> %d %d %d %llu
    ",x,y,z,dp[f[y]]);
        if(dp[f[y]][x&4095])return 0;
      }
      return 1;
    }
    int main (){
      freopen ( "input.txt" , "r" , stdin ) ;
      freopen ( "output.txt" , "w" , stdout ) ;
      fread(Buf,1,BUF,stdin);
      read(n),read(m);
      for(i=1;i<=m;i++){
        //x=i,y=i+1;
        read(x),read(y);
        ans[i][0]=x,ans[i][1]=y;
        add(x,y);
        add2(y,x);
      }
      
      for(i=1;i<=n;i++)if(!vis[i])dfs1(i);
      for(i=n;i;i--)if(vis[q[i]])dfs2(q[i],++cnt);
      
      for(ed=0,i=1;i<=cnt;i++)g[i]=0;
      for(i=1;i<=m;i++){
        x=ans[i][0],y=ans[i][1];
        if(f[x]==f[y])continue;
        if(SET[f[x]].find(f[y])!=SET[f[x]].end())continue;
        SET[f[x]].insert(f[y]);
        add(f[x],f[y]);
        d[f[y]]++;
      }
      for(h=1,t=0,i=1;i<=cnt;i++)if(!d[i])q[++t]=i;
      while(h<=t)for(i=g[q[h++]];i;i=nxt[i])if(!(--d[v[i]]))q[++t]=v[i];
      //now q is topo sequence of SCC
      
      read(quailty);
      for(i=1;i<=quailty;i++){
        //e[i].x=i+1;
        //e[i].y=i;
        read(e[i].x),read(e[i].y);
        e[i].z=e[i].x>>12;
      }
      sort(e+1,e+quailty+1,cmp);
      for(i=1;i<=quailty;i=j){
        for(j=i;j<=quailty&&e[i].z==e[j].z;j++);
        if(!solve(i,j-1))return puts("NO"),0;
      }
      puts("YES");
      printf("%d
    ",m);
      for(i=1;i<=m;i++)printf("%d %d
    ",ans[i][0],ans[i][1]);
      return 0 ;
    }
    

      

    D. Housing payments

    设$f[i]$表示前$i$个月付清,且第$i$个月进行了交易的最小代价,那么因为债务指数级增长,所以可用决策只有$O(log n)$项。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef pair < int , int > pii ;
    
    const int MAXN = 100005 ;
    const int INF = 0x3f3f3f3f ;
    
    int s[MAXN] , x[MAXN] , p[MAXN] ;
    double dp[MAXN] ;
    int n ;
    
    void solve () {
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		scanf ( "%d%d%d" , &s[i] , &x[i] , &p[i] ) ;
    		dp[i] = 1e18 ;
    	}
    	dp[0] = 0 ;
    	for ( int i = 0 ; i <= n ; ++ i ) {
    		double sum1 = 0 ;
    		for ( int j = i + 1 ; j <= i + 100 && j <= n ; ++ j ) {
    			dp[j] = min ( dp[j] , dp[i] + sum1 + s[j] + x[j] ) ;
    			sum1 = ( sum1 + s[j] ) * ( 1 + 0.01 * p[j] ) ;
    		}
    	}
    	printf ( "%.10f
    " , dp[n] ) ;
    }
    
    int main () {
    	freopen ( "input.txt" , "r" , stdin ) ;
    	freopen ( "output.txt" , "w" , stdout ) ;
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    E. Arithmetic expressions

    $f[i][j]$表示长度为$i$的值为$j$的表达式个数,然后枚举后面接上什么转移即可。

    #include <bits/stdc++.h>
    using namespace std ;
    const int mod=1e9+7;
    int n,m,p;
    int dp[55][222];
    int len[333];
    void up(int &x,int y){x+=y;if(x>=mod)x-=mod;}
    int main () {
    	freopen ( "input.txt" , "r" , stdin ) ;
    	freopen ( "output.txt" , "w" , stdout ) ;
    	while(scanf("%d%d%d",&n,&m,&p)!=EOF){
    		memset(dp,0,sizeof dp);
    		for(int i=0;i<m;i++){
    			int x=i;
    			if(!x){len[i]=1;continue;}
    			int l=0;
    			while(x)l++,x/=10;
    			len[i]=l;
    		}
    		for(int i=1;i<=n;i++){
    			for(int j=0;j<m;j++){
    				if(len[j]==i)up(dp[i][j],1);
    				if(i>=3)up(dp[i][j],dp[i-2][j]);
    			}
    			//if(i==2)up(dp[i][0],1);
    			for(int j=0;j<m;j++){
    				for(int k=1;k+1<i;k++){
    					int nj,ni=i-k-1;
    					for(int nm=0;nm<m;nm++){
    						for(int ty=0;ty<2;ty++){
    							if(!ty)nj=(j+nm)%m;
    							else nj=(j-nm+m)%m;
    							if(ni>2)up(dp[i][nj],1LL*dp[k][j]*dp[ni-2][nm]%mod);
    							if(len[nm]==ni)up(dp[i][nj],dp[k][j]);
    						}
    					}
    				}
    			}
    		}
    		printf("%d
    ",dp[n][p]);
    	}
            return 0;
    }
    

      

    F. Sputnik

    留坑。

    G. Voting

    设$f[i][j]$表示$i$的子树里选举情况为$j$的最小代价,转移则用另一个$dp[i][a][b][c]$表示考虑了前$i$个儿子,三个人选票各自为$a,b,c$的最小代价来转移。

    #include <bits/stdc++.h>
    using namespace std ;
    const int mod=1e9+7;
    const int Maxn=10050,M=10,Inf=1e9;
    typedef pair<int,int>pi;
    int n,m,K;
    vector<int>G[Maxn];
    int f[Maxn][4];
    int g[23][23][23][23];
    int ori[Maxn];
    vector<pi>ans;
    vector<pi>res[Maxn][4];
    pi pre[23][23][23][23];
    void init(int cs){
    	for(int i=0;i<21;i++){
    		for(int j=0;j<21;j++){
    			for(int k=0;k<21;k++)
    				g[cs][i][j][k]=Inf;
    		}
    	}
    }
    struct State{
    	int x,y,z;
    	State(){}
    	State(int x,int y,int z):x(x),y(y),z(z){}
    }st[Maxn][4];
    int get(int a,int b,int c){
    	vector<pi>v;
    	v.push_back(pi(a,1));
    	v.push_back(pi(b,2));
    	v.push_back(pi(c,3));
    	sort(v.begin(),v.end());
    	reverse(v.begin(),v.end());
    	if(v[0].first==v[1].first)return 0;
    	return v[0].second;
    }
    void dfs(int u){
    	if(u>m){
    		for(int i=0;i<4;i++){
    			if(i>K)f[u][i]=Inf;
    			else {
    				res[u][i].push_back(pi(u,i));
    				f[u][i]=i==ori[u]?0:1;
    			}
    		}
    		return ;
    	}
    	for(int i=0;i<G[u].size();i++){
    		int v=G[u][i];
    		dfs(v);
    	}
    	int n=G[u].size();
    	init(0);
    	g[0][0][0][0]=0;
    	for(int i=0;i<n;i++){
    		int v=G[u][i];
    		init(i+1);
    		int it[4];
    		for(it[0]=0;it[0]<=20;it[0]++)
    		for(it[1]=0;it[1]<=20;it[1]++)
    		for(it[2]=0;it[2]<=20;it[2]++){
    			if(g[i][it[0]][it[1]][it[2]]==Inf)continue;
    			int w=g[i][it[0]][it[1]][it[2]];
    			for(int ty=0;ty<4;ty++){
    				if(f[v][ty]==Inf)continue;
    				if(ty)it[ty-1]++;
    				int nw=w+f[v][ty];
    				int &t=g[i+1][it[0]][it[1]][it[2]];
    				if(nw<t){
    					t=nw;
    					pre[i+1][it[0]][it[1]][it[2]]=pi(v,ty);
    				}
    				if(ty)it[ty-1]--;
    			}
    		}
    	}
    	for(int i=0;i<4;i++)f[u][i]=Inf;
    	for(int i=0;i<=20;i++){
    		for(int j=0;j<=20;j++){
    			for(int k=0;k<=20;k++){
    				if(g[n][i][j][k]==Inf)continue;
    				int ty=get(i,j,k);
    				if(f[u][ty]>g[n][i][j][k]){
    					f[u][ty]=g[n][i][j][k];
    					st[u][ty]=State(i,j,k);
    				}
    			}
    		}
    	}
    	for(int i=0;i<4;i++){
    		if(f[u][i]==Inf)continue;
    		res[u][i].clear();
    		State tmp=st[u][i];
    		for(int cur=n;cur>=1;cur--){
    			res[u][i].push_back(pre[cur][tmp.x][tmp.y][tmp.z]);
    			int ty=pre[cur][tmp.x][tmp.y][tmp.z].second;
    			if(ty==1)tmp.x--;
    			if(ty==2)tmp.y--;
    			if(ty==3)tmp.z--;
    		}
    		reverse(res[u][i].begin(),res[u][i].end());
    	}
    	//printf("u=%d
    ",u);
    	//for(int i=0;i<4;i++)printf("%d ",f[u][i]);puts("");
    }
    void dfs2(int u,int ty){
    	//printf("u=%d ty=%d
    ",u,ty);
    	if(u>m){
    		if(ori[u]!=ty)ans.push_back(pi(u,ty));
    		return;
    	}
    	//printf("sz=%d
    ",(int)res[u][1].size());
    	for(int i=0;i<G[u].size();i++){
    		//printf("v=%d
    ",G[u][i]);
    		dfs2(G[u][i],res[u][ty][i].second);
    	}
    }
    int main () {
    	freopen ( "input.txt" , "r" , stdin ) ;
    	freopen ( "output.txt" , "w" , stdout ) ;
    	scanf("%d%d%d",&n,&m,&K);
    	for(int i=1;i<=n;i++)scanf("%d",&ori[i+m]);
    	for(int i=1;i<=m;i++){
    		int k;scanf("%d",&k);
    		for(int j=0;j<k;j++){
    			int x;scanf("%d",&x);
    			if(x<0)x=-x;
    			else x=m+x;
    			G[i].push_back(x);
    		}
    	}
    	dfs(1);
    	//puts("ok1");
    	dfs2(1,1);
    	printf("%d
    ",(int)ans.size());
    	for(int i=0;i<ans.size();i++)printf("%d %d
    ",ans[i].first-m,ans[i].second);
            return 0;
    }
    

      

    H. Novice urbanist

    枚举每个点和每个区间,那么它能贡献的距离是一段区间,差分前缀和即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    int n,m,l,r,cnt,i,j;
    int a[11111],f[4444444];
    struct P{int l,r;P(){}P(int _l,int _r){l=_l,r=_r;}}b[1111],c[1111];
    inline bool cmp(const P&a,const P&b){return a.l<b.l;}
    
    int main () {
      freopen ( "input.txt" , "r" , stdin ) ;
      freopen ( "output.txt" , "w" , stdout ) ;
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;i++)scanf("%d",&a[i]);
      for(i=1;i<=m;i++)scanf("%d%d",&b[i].l,&b[i].r);
      sort(b+1,b+m+1,cmp);
      l=1e9;
      r=-l;
      for(i=1;i<=m;i++){
        if(b[i].l>r+1){
          if(l<=r)c[++cnt]=P(l,r);
          l=b[i].l;
        }
        r=max(r,b[i].r);
      }
      if(l<=r)c[++cnt]=P(l,r);
      for(i=1;i<=n;i++){
        for(j=1;j<=cnt;j++){
          f[c[j].l-a[i]+2000000]++;
          f[c[j].r-a[i]+2000000+1]--;
        }
      }
      for(i=1;i<4000000;i++)f[i]+=f[i-1];
      int ans=-1,ans2;
      for(i=0;i<2000000;i++){
        int t=max(f[2000000+i],f[2000000-i]);
        if(t>ans)ans=t,ans2=i;
      }
      printf("%d %d",ans2,ans);
      return 0 ;
    }
    

      

    I. Rangefinder

    留坑。

    J. Hive

    求出方向向量$(x,y)$,顺时针旋转$60$°后是$(x+y,-x)$。

    #include <bits/stdc++.h>
    using namespace std ;
    const int Maxn=100020;
    int n,x,y,a,b;
    int main () {
    	freopen ( "input.txt" , "r" , stdin ) ;
    	freopen ( "output.txt" , "w" , stdout ) ;
    	scanf("%d%d%d",&n,&x,&y);
    	while(n--){
    	  scanf("%d%d",&a,&b);
    	  a-=x,b-=y;
    	  printf("%d %d
    ",x+a+b,y-a);
            }
            return 0;
    }
    

      

    K. Side effects

    每次加入一条边之后暴力染色,然后将经过的边删掉,均摊复杂度$O(n+m)$。

    #include <bits/stdc++.h>
    using namespace std ;
    const int Maxn=100020;
    int n,m,q,ans;
    set<int>G[Maxn];
    int col[Maxn];
    void dfs(int u){
    	//printf("u=%d
    ",u);
    	col[u]=1;
    	for(set<int>::iterator it=G[u].begin();it!=G[u].end();){
    		//printf("iv=%d
    ",*it);
    		if(!col[*it]){
    			dfs(*it);
    			ans++;
    		}
    		G[u].erase(it++);
    	}
    }
    void solve(){
    	ans=0;
    	for(int i=1;i<=m;i++){
    		int x;scanf("%d",&x);
    		col[x]=1;
    		ans++;
    	}
    	while(q--){
    		//puts("ok");
    		int u,v;scanf("%d%d",&u,&v);
    		if(u!=v)G[v].insert(u);
    		if(col[v]==1)dfs(v);
    		printf("%d
    ",ans);
    	}
    }
    int main () {
    	freopen ( "input.txt" , "r" , stdin ) ;
    	freopen ( "output.txt" , "w" , stdout ) ;
    	while ( ~scanf ( "%d%d%d" , &n,&m,&q ) ) solve () ;
    	return 0 ;
    }
    

      

    L. Cypher

    留坑。


    总结:

    • 在分块bitset时,应尽量设大bitset的大小,减少bitset的操作次数,这样常数反而小。
  • 相关阅读:
    Pwn-warmup_csaw_2016 writeup
    操作系统习题总结
    操作系统-存储器管理部分(待更新)
    树与二叉树之间的互相转换
    黑客攻防技术宝典-反病毒篇笔记(三)
    jaegeropentracing的Java-client完整分布式追踪链
    jaegeropentracing的Java-client
    IDEA2018.2版本注册
    Spring整合CXF webservice restful 实例
    带有WS-Security验证的webservice
  • 原文地址:https://www.cnblogs.com/clrs97/p/6049408.html
Copyright © 2011-2022 走看看