• 2015 ACM Syrian Collegiate Programming Contest


    A. My Friend of Misery

    计算出答案的上下界即可。

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

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100010;
    typedef long long LL;
    int main(){
    	int _;scanf("%d",&_);
    	while(_--){
    		int n;scanf("%d",&n);
    		LL cur=0,r=1LL<<60;
    		while(n--){
    			int x;char c;
    			scanf("%d %c",&x,&c);
    			if(c=='-'){
    				r=min(r,cur+x+25);
    			}
    			else{
    				cur+=x+25;
    			}
    			//printf("%lld
    ",r-cur);
    		}printf("%lld
    ",r-cur);
    	}
    }
    

      

    B. Brother Louie

    纵坐标根据深度即可计算,比较麻烦的是横坐标。

    设最左边的叶子的横坐标为$t$,那么每个点的横坐标都能表示为$t+A_ir+B_ih$,根据$x_{root}=0$,可以解出$t$,然后就可以计算出对应点的横坐标。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=100010;
    int T,n,m,i,j,a[N],f[N],son[N][2],root;
    int d[N],cnt;
    double A[N],B[N];//t+A*r+B*h
    void dfs(int x,int y){
      d[x]=y;
      if(!a[x]){
        A[x]=cnt*2;
        B[x]=cnt;
        cnt++;
        return;
      }
      for(int i=0;i<2;i++)dfs(son[x][i],y+1);
      A[x]=(A[son[x][0]]+A[son[x][1]])/2.0;
      B[x]=(B[son[x][0]]+B[son[x][1]])/2.0;
    }
    inline double askx(double r,double h,int x){
      return (A[x]-A[root])*r+(B[x]-B[root])*h;
    }
    inline double asky(double r,double v,int x){
      return -(r*2+v)*d[x];
    }
    int main(){
      scanf("%d",&T);
      while(T--){
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++){
          scanf("%d",&a[i]);
          if(a[i]){
            for(j=0;j<2;j++){
              scanf("%d",&son[i][j]);
              f[son[i][j]]=i;
            }
          }
        }
        for(i=1;i<=n;i++)if(!f[i])root=i;
        dfs(root,0);
        while(m--){
          double r,v,h;int x;
          scanf("%lf%lf%lf%d",&r,&v,&h,&x);
          printf("%.4f %.4f
    ",askx(r,h,x),asky(r,v,x));
        }
        root=cnt=0;
        for(i=0;i<=n;i++){
          a[i]=f[i]=son[i][0]=son[i][1]=d[i]=0;
          A[i]=B[i]=0;
        }
      }
      return 0;
    }
    

      

    C. Everything

    建立Trie树,dfs一遍得到每个串的字典序,然后枚举前缀,根据排名更新答案即可。

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

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=100010,M=500010;
    int T,n,i,j,pos[N],rk[N],cnt,ans[N];
    int tot,son[M][26],id[M],d[M],f[M];
    int m,q[N],g[M],v[M],nxt[M],ed;
    char s[N];
    inline bool cmp(int x,int y){return rk[x]<rk[y];}
    inline void ins(int p){
      scanf("%s",s);
      int l=strlen(s),x,i;
      for(x=0,i=0;i<l;i++){
        int w=s[i]-'a';
        if(!son[x][w]){
          son[x][w]=++tot;
          f[tot]=x;
        }
        x=son[x][w];
      }
      pos[p]=x;
      id[x]=p;
    }
    void dfs(int x,int y){
      d[x]=y;
      if(id[x])rk[id[x]]=++cnt;
      for(int i=0;i<26;i++)if(son[x][i])dfs(son[x][i],y+1);
    }
    inline void deal(int x){
      for(int i=pos[x];i;i=f[i]){
        v[++ed]=x;
        nxt[ed]=g[i];
        g[i]=ed;
      }
    }
    inline int cal(int n,int x){
      return min(x,n-x+2);
    }
    inline void solve(int x){
      m=0;
      for(int i=g[x];i;i=nxt[i])q[++m]=v[i];
      if(!m)return;
      sort(q+1,q+m+1,cmp);
      for(int i=1;i<=m;i++)ans[q[i]]=min(ans[q[i]],d[x]+cal(m,i));
    }
    int main(){
      scanf("%d",&T);
      while(T--){
        scanf("%d",&n);
        for(i=1;i<=n;i++)ins(i);
        dfs(0,0);
        for(i=1;i<=n;i++)ans[i]=cal(n,rk[i]);
        for(i=1;i<=n;i++)deal(i);
        for(i=1;i<=tot;i++)solve(i);
        for(i=1;i<=n;i++)printf("%d%c",ans[i],i<n?' ':'
    ');
        for(i=0;i<=tot;i++){
          g[i]=id[i]=d[i]=f[i]=0;
          for(j=0;j<26;j++)son[i][j]=0;
        }
        cnt=ed=tot=0;
      }
      return 0;
    }
    

      

    D. Secure but True

    首先计算出答案串的长度,然后看成11进制下的高精度加法即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 100005 ;
    typedef long long LL;
    char s[]={'A', 'H', 'I', 'M', 'O', 'T', 'U', 'V', 'W', 'X', 'Y'};
    int id[333];
    char ss[1020];
    int a[1020],b[1020];
    int c[1020];
    LL sum[1020],pww[1020];
    const LL Inf=1LL<<50;
    void upd(LL &pw){
    	pw*=11;
    	if(pw>=Inf)pw=Inf;
    }
    void solve () {
    	int x;
    	scanf("%d",&x);
    	scanf("%s",ss);
    	int cnt2=strlen(ss);
    	for(int i=0;ss[i];i++)b[i]=id[ss[i]];
    	LL pw=1,cursum=0,sel=-1;
    	sum[cnt2]=0;
    	for(int i=cnt2-1;i>=0;i--,upd(pw)){
    		LL cost=(10-b[i])*pw;
    		cursum+=cost;
    		sum[i]=cursum;
    		pww[i]=pw;
    		if(cursum>=x){
    			sel=i;
    			break;
    		}
    	}
    	//printf("sel=%lld
    ",sel);
    	if(sel>=0){
    		x-=sum[sel+1]+1;
    		b[sel]+=x/pww[sel]+1;
    		x%=pww[sel];
    		for(int i=sel+1;i<cnt2;i++)b[i]=0;
    		int curloc=cnt2-1;
    		while(x){b[curloc--]=x%11;x/=11;}
    		for(int i=0;i<cnt2;i++)printf("%c",s[b[i]]);puts("");
    		return ;
    	}
    	x-=cursum;
    	//printf("x=%d
    ",x);
    	pw=pww[0];
    	upd(pw);upd(pw);
    	//printf("pw=%lld
    ",pw);
    	int len=cnt2;
    	if(x>1){
    		while(x>pw)x-=pw,pw*=11,len++;
    	}
    	len++;
    	//printf("x=%d
    ",x);
    	for(int i=0;i<len;i++){
    		c[i]=0;
    	}
    	x--;
    	int cnt3=0;
    	while(x){c[cnt3++]=x%11;x/=11;}
    	reverse(c,c+len);
    	for(int i=0;i<len;i++)printf("%c",s[c[i]]);puts("");
    }
    
    int main () {
    	for(int i=0;i<11;i++)id[s[i]]=i;
    	int T ;
    	scanf ( "%d" , &T ) ;
    	for ( int i = 1 ; i <= T ; ++ i ) {
    		solve () ;
    	}
    	return 0 ;
    }
    

      

    E. Going in Circles

    切割点只可能是2个,3个或者4个。

    首先特判掉整个环全部都是小写字母的情况,然后将每段小写字符压缩成一块,并计算出在每块内部切割的方案数。

    枚举每种大写字符,可以得到要切割的两部分应该分布在哪些范围内,设$f[i][j]$为第$i$个字符下某个切割块所属的连通块编号,对$f$进行Hash,那么一定是在Hash值相同的里面选取两个块,每块切1~2刀。

    时间复杂度$O(n(26+log n))$。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=50010;
    const int BASE=10007;
    typedef long long ll;
    typedef unsigned long long ull;
    char a[N];
    int block;
    int T,n,m,i,j,k,f[N],q[N];
    int id[N],size[N],vis[N];
    ll C2[N],C3[N],C4[N],ans;
    ull h[N];
    inline bool cmp(int x,int y){return h[x]<h[y];}
    inline bool small(char x){return x>='a'&&x<='z';}
    int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    inline void merge(int x,int y){
      if(F(x)!=F(y))f[f[x]]=f[y];
    }
    inline bool special(){
      for(int i=0;i<n;i++)if(!small(a[i]))return 0;
      return 1;
    }
    inline ll solvespecial(){
      return C2[n]+C2[3]*C3[n]+2LL*C4[n];
    }
    inline void update(int l,int r,int p){
      for(int i=l;i<=r;i++){
        int x=id[f[i]];
        if(vis[x])continue;
        vis[x]=1;
        h[x]+=p;
      }
    }
    inline ll solveoneblock(int n){
      return C2[n]+2LL*C3[n]+C4[n];
    }
    int main(){
      for(i=1;i<N;i++){
        C2[i]=1LL*i*(i-1)/2;
        C3[i]=1LL*i*(i-1)*(i-2)/6;
        C4[i]=1LL*i*(i-1)*(i-2)*(i-3)/24;
      }
      scanf("%d",&T);
      while(T--){
        scanf("%s",a);
        n=strlen(a);
        if(special()){
          printf("%lld
    ",2LL*solvespecial());
          continue;
        }
        for(i=0;i<n;i++)f[i]=i;
        for(i=0;i<n;i++){
          //the divide between i and (i+1)%n
          if(small(a[i]))merge((i-1+n)%n,i);
        }
        for(i=0;i<n;i++)id[i]=0;
        for(i=1;i<=n;i++)size[i]=0;
        block=0;
        for(i=0;i<n;i++){
          if(!id[F(i)]){
            id[f[i]]=++block;
          }
          size[id[f[i]]]++;
        }
        ans=0;
        for(i=1;i<=block;i++)h[i]=0;
        for(char O='A';O<='Z';O++){
          for(i=1;i<=block;i++)h[i]*=BASE,vis[i]=0;
          m=0;
          for(i=0;i<n;i++)if(a[i]==O)q[m++]=i;
          for(i=1;i<m;i++){
            update(q[i-1],q[i]-1,i);
          }
        }
        //printf("block=%d
    ",block);
        //for(i=0;i<n;i++)printf("%d ",f[i]);puts("");
        for(i=1;i<=block;i++){
          ans+=solveoneblock(size[i]);
         // printf("%d %d %lld
    ",i,size[i],solveoneblock(size[i]));
        }
        //ans=0;
        for(i=1;i<=block;i++)q[i]=i;
        sort(q+1,q+block+1,cmp);
        for(i=1;i<=block;i=j){
          ll sum=0;
          for(j=i;j<=block&&h[q[i]]==h[q[j]];j++);
          for(k=i;k<j;k++){
            ll ret=C2[size[q[k]]]+size[q[k]];
            //printf("%d %d %lld
    ",q[k],size[q[k]],ret);
            //printf("%llu %d %d %lld %lld
    ",h[q[k]],q[k],size[q[k]],ret,sum);
            ans+=ret*sum;
            sum+=ret;
          }
          //[i,j)
        }
        printf("%lld
    ",2LL*ans);
      }
      return 0;
    }
    

      

    F. Hey JUDgE

    暴力枚举所有合并情况然后检验即可。

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

    #include<cstdio>
    #include<iostream>
    #include<string>
    using namespace std;
    string s;
    int T;
    inline bool check(string s){
      static bool v[11];
      for(int i=0;i<11;i++)v[i]=0;
      for(int i=0;i<7;i++)v[s[i]]=1;
      for(int i=1;i<=5;i++)if(!v[i])return 0;
      return 1;
    }
    bool solve(){
      int i,j,a,b;
      cin>>s;
      for(i=0;i<7;i++)s[i]=s[i]-'A'+1;
      if(check(s))return 1;
      for(i=0;i<7;i++)
        for(j=0;j<i;j++){
          string t=s;
          t[i]+=t[j];
          t[j]=0;
          if(check(t))return 1;
        }
      for(i=0;i<7;i++)
        for(j=0;j<i;j++)
          for(a=0;a<7;a++)
            for(b=0;b<a;b++){
              if(i==a)continue;
              if(i==b)continue;
              if(j==a)continue;
              if(j==b)continue;
              string t=s;
              t[i]+=t[j];
              t[j]=0;
              t[a]+=t[b];
              t[b]=0;
              if(check(t))return 1;
            }
      return 0;
    }
    int main(){
      cin>>T;
      while(T--){
        puts(solve()?"YES":"NO");
      }
    }
    

      

    G. Paradise City

    按题意模拟即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 303 ;
    
    char s[MAXN][MAXN] ;
    
    void solve () {
    	int n ;
    	scanf ( "%d" , &n ) ;
    	for ( int i = 1 ; i <= 3 ; ++ i ) {
    		scanf ( "%s" , s[i] + 1 ) ;
    	}
    	int ans = 0 ;
    	for ( int i = 1 ; i <= 3 ; ++ i ) {
    		for ( int j = 1 ; j <= 3 * n ; ++ j ) if ( s[i][j] == 'X' ) {
    			int t = 0 ;
    			for ( int x = -1 ; x <= 1 ; ++ x ) {
    				for ( int y = -1 ; y <= 1 ; ++ y ) if ( x || y ) {
    					int nx = i + x ;
    					int ny = j + y ;
    					if ( nx < 1 || nx > 3 || ny < 1 || ny > 3 * n ) continue ;
    					if ( s[nx][ny] == '*' ) t += 4 ;
    				}
    			}
    			ans = max ( ans , t ) ;
    		}
    	}
    	printf ( "%d
    " , ans ) ;
    }
    
    int main () {
    	int T ;
    	scanf ( "%d" , &T ) ;
    	for ( int i = 1 ; i <= T ; ++ i ) {
    		solve () ;
    	}
    	return 0 ;
    }
    

      

    H. Another Square in the Floor

    $ans=max^2(X,Y)$。

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
    	int _;scanf("%d",&_);
    	while(_--){
    		int n,m;
    		scanf("%d%d",&n,&m);
    		printf("%d
    ",max(n,m)*max(n,m));
    	}
    }
    

      

    I. Home Sweet Home

    枚举前导零的个数,然后从两边同时开始数位DP即可,一边从高位到低位转移,另一边从低位到高位转移。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 100005 ;
    
    typedef long long LL;
    int a[44],b[44];
    LL dp1[66][2][2];
    LL dp2[50][50][2][2][3][3];
    int get(int x,int y){
    	if(x==y)return 0;
    	if(x<y)return 1;
    	return 2;
    }
    int check(int can1,int can2,int ncan1,int ncan2){
    	if(!can1&&ncan1==2)return 0;	
    	if(!can2&&ncan2==2)return 0;	
    	return 1;
    }
    LL dfs2(int cur,int totlen,int can1,int can2,int lcan1,int lcan2){
    	if(!totlen)return check(can1,can2,lcan1,lcan2);
    	if(totlen%2==0&&cur>=totlen/2)return check(can1,can2,lcan1,lcan2);
    	LL &ret=dp2[cur][totlen][can1][can2][lcan1][lcan2];
    	if(ret>=0)return ret;
    	ret=0;
    	int x1=a[totlen-cur],x2=b[totlen-cur];
    	int lx1=a[cur+1],lx2=b[cur+1];
    	if((totlen%2==1)&&(cur==totlen/2)){
    		for(int t1=0;t1<2;t1++)
    		for(int t2=0;t2<2;t2++){
    			if(t1>x1&&!can1)continue;
    			if(t2>x2&&!can2)continue;
    			int ncan1=can1||(t1<x1);
    			int ncan2=can2||(t2<x2);
    			ret+=check(ncan1,ncan2,lcan1,lcan2);
    		}
    		return ret;
    	}
    	for(int t1=0;t1<2;t1++)
    	for(int t2=0;t2<2;t2++){
    		if(t1>x1&&!can1)continue;
    		if(t2>x2&&!can2)continue;
    		int ncan1=can1||(t1<x1);
    		int ncan2=can2||(t2<x2);
    		for(int lt1=0;lt1<2;lt1++)
    		for(int lt2=0;lt2<2;lt2++){
    			if((lt1^lt2)!=(t1^t2))continue;
    			int nlcan1=get(lt1,lx1);if(!nlcan1)nlcan1=lcan1;
    			int nlcan2=get(lt2,lx2);if(!nlcan2)nlcan2=lcan2;
    			ret+=dfs2(cur+1,totlen,ncan1,ncan2,nlcan1,nlcan2);
    		}
    	}
    	return ret;
    }
    LL dfs1(int cur,int can1,int can2){
    	if(cur<0)return 1;
    	LL &ret=dp1[cur][can1][can2];
    	if(ret>=0)return ret;
    	ret=0;
    	for(int t1=0;t1<2;t1++)
    	for(int t2=0;t2<2;t2++){
    		if(t1>a[cur]&&!can1)continue;
    		if(t2>b[cur]&&!can2)continue;
    		int ncan1=can1||(t1<a[cur]);
    		int ncan2=can2||(t2<b[cur]);
    		if(!(t1^t2)){
    			ret+=dfs1(cur-1,ncan1,ncan2);
    		}
    		else{
    			if(!cur){ret++;continue;}
    			for(int lt1=0;lt1<2;lt1++)
    			for(int lt2=0;lt2<2;lt2++){
    				if((lt1^lt2)!=1)continue;
    				int nlt1=get(lt1,a[0]);
    				int nlt2=get(lt2,b[0]);
    				ret+=dfs2(0,cur-1,ncan1,ncan2,nlt1,nlt2);
    			}
    		}
    	}
    	return ret;
    }
    LL solve(LL x,LL y){
    	for(int i=0;i<43;i++){a[i]=x&1;x>>=1;}
    	for(int i=0;i<43;i++){b[i]=y&1;y>>=1;}
    	memset(dp1,-1,sizeof dp1);
    	memset(dp2,-1,sizeof dp2);
    	LL ret=dfs1(42,0,0);
    	return ret;
    }
    void go () {
    	LL L,R;
    	scanf("%lld%lld",&L,&R);
    	
    		//printf("ans1=%lld
    ",solve(0,4));
    		//printf("ans2=%lld
    ",solve(4,0));
    		//return ;
    	LL ans=solve(R,R);
    	//printf("ans=%lld
    ",ans);
    	if(L)ans-=solve(L-1,R);
    	//printf("ans=%lld
    ",ans);
    	if(L)ans-=solve(R,L-1);
    	//printf("ans=%lld
    ",ans);
    	if(L)ans+=solve(L-1,L-1);
    	printf("%lld
    ",ans);
    }			
    
    int main () {
    	int T ;
    	scanf ( "%d" , &T ) ;
    	for ( int i = 1 ; i <= T ; ++ i ) {
    		go () ;
    	}
    	return 0 ;
    }
    

      

    J. Smooth Developer

    按题意模拟即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 100005 ;
    
    map < string , int > mp1 ;
    map < int , string > mp2 ;
    int n , m , cnt ;
    vector < int > G[MAXN] ;
    int vis[MAXN] ;
    char s[20] ;
    
    int get () {
    	scanf ( "%s" , s ) ;
    	if ( mp1.count ( s ) ) return mp1[s] ;
    	++ cnt ;
    	mp1[s] = cnt ;
    	mp2[cnt] = s ;
    	return cnt ;
    }
    
    void dfs ( int u ) {
    	if ( vis[u] ) return ;
    	vis[u] = 1 ;
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i] ;
    		dfs ( v ) ;
    	}
    }
    
    void solve () {
    	cnt = 0 ;
    	mp1.clear () ;
    	mp2.clear () ;
    	scanf ( "%d%d" , &n , &m ) ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		G[i].clear () ;
    		vis[i] = 0 ;
    	}
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		int u = get () , c ;
    		scanf ( "%d" , &c ) ;
    		for ( int j = 0 ; j < c ; ++ j ) {
    			int v = get () ;
    			G[u].push_back ( v ) ;
    		}
    	}
    	for ( int i = 1 ; i <= m ; ++ i ) {
    		int u = get () ;
    		dfs ( u ) ;
    	}
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		if ( vis[i] ) cout << mp2[i] << endl ;
    	}
    }
    
    int main () {
    	int T ;
    	scanf ( "%d" , &T ) ;
    	for ( int i = 1 ; i <= T ; ++ i ) {
    		solve () ;
    	}
    	return 0 ;
    }
    

      

    K. Betrayed

    首先对于每棵树两遍DP求出以每个点为根的最大深度,就可以得到每棵树爆栈的概率,递推求出期望步数即可。

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

    #include <bits/stdc++.h>
    using namespace std ;
    
    const int MAXN = 100005 ;
    
    typedef long long LL;
    
    vector < int > G[MAXN] ;
    int dp[MAXN] , dp2[MAXN] ;
    double p[22] ;
    double f[22] ;
    //double a[22][22] ;
    int C , K , n ;
    
    void dfs2 ( int u , int f ) {
    	int maxv = 0 ;
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i] ;
    		if ( v == f ) continue ;
    		dp2[v] = max ( dp2[u] + 1 , maxv ) ;
    		maxv = max ( maxv , dp[v] + 2 ) ;
    	}
    	maxv = 0 ;
    	for ( int i = G[u].size () - 1 ; ~i ; -- i ) {
    		int v = G[u][i] ;
    		if ( v == f ) continue ;
    		dp2[v] = max ( dp2[v] , maxv ) ;
    		maxv = max ( maxv , dp[v] + 2 ) ;
    	}
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i] ;
    		if ( v == f ) continue ;
    		dfs2 ( v , u ) ;
    	}
    }
    
    void dfs ( int u , int f ) {
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i] ;
    		if ( v == f ) continue ;
    		dfs ( v , u ) ;
    		dp[u] = max ( dp[u] , dp[v] + 1 ) ;
    	}
    }
    /*
    void gauss ( int n , int m ) {
    	int r = 0 , c = 0 ;
    	for ( ; r < n && c < m ; ++ c ) {
    		int tr = r ;
    		for ( int i = r ; i < n ; ++ i ) {
    			if ( a[i][c] > a[tr][c] ) tr = i ;
    		}
    		if ( fabs ( a[tr][c] ) < 1e-8 ) continue ;
    		for ( int i = c ; i <= C ; ++ i ) {
    			swap ( a[r][i] , a[tr][i] ) ;
    		}
    		for ( int i = C ; i >= c ; -- i ) a[r][i] /= a[r][c] ;
    		for ( int i = 0 ; i < n ; ++ i ) if ( i != r && fabs ( a[i][c] ) > 1e-8 ) {
    			for ( int j = C ; j >= c ; -- j ) {
    				a[i][j] -= a[r][j] * a[i][c] ;
    			}
    		}
    		++ r ;
    	}
    	for ( int i = r - 1 ; i ; -- i ) {
    		for ( int j = 
    	}
    }
    */
    void solve () {
    	scanf ( "%d%d" , &C , &K ) ;
    	for ( int i = 1 ; i <= C ; ++ i ) {
    		scanf ( "%d" , &n ) ;
    		for ( int j = 1 ; j <= n ; ++ j ) {
    			G[j].clear () ;
    			dp[j] = dp2[j] = 0  ;
    		}
    		for ( int j = 2 , x ; j <= n ; ++ j ) {
    			scanf ( "%d" , &x ) ;
    			G[j].push_back ( x ) ;
    			G[x].push_back ( j ) ;
    		}
    		dfs ( 1 , 1 ) ;
    		dfs2 ( 1 , 1 ) ;
    		int cnt = 0 ;
    		for ( int j = 1 ; j <= n ; ++ j ) {
    			if ( max ( dp2[j] , dp[j] ) <= K ) ++ cnt ;
    		}
    		p[i] = 1.0 * cnt / n ; 
    		//a[i][i] = 1 ;
    		//a[i][i + 1] = -p[i] ;
    		//a[i][0] = ( 1 - p[i] ) ;
    		//a[i][C] = 4 - 3 * p[i] ;
    	}
    	double pp = 1 ;
    	f[1] = -3 ;
    	for ( int i = C ; i >= 1 ; -- i ) {
    		pp *= p[i] ;
    		if ( i > 1 ) f[1] += 1.0 / pp ;
    		else f[1] += 4.0 / pp ;
    	}
    	printf ( "%.4f
    " , f[1] ) ;
    	//a[C][C] = 1 ;
    	//gauss ( C + 1 , C + 1 ) ;
    }			
    
    int main () {
    	int T ;
    	scanf ( "%d" , &T ) ;
    	for ( int i = 1 ; i <= T ; ++ i ) {
    		solve () ;
    	}
    	return 0 ;
    }
    

      

    L. Chance

    预处理出$f[i]$表示$[1,i]$中二进制下1的个数为素数的个数,然后$O(1)$回答即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100010;
    int f[N],vis[N];
    int main(){
    	vis[1]=1;
    	for(int i=2;i<N;i++)if(!vis[i])for(int j=i+i;j<N;j+=i)vis[j]=1;
    	int _;scanf("%d",&_);
    	for(int i=1;i<=100000;i++){
    		f[i]=f[i-1];
    		if(!vis[__builtin_popcount(i)])f[i]++;
    	}
    	while(_--){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		if(!l)l=1;
    		printf("%d
    ",f[r]-f[l-1]);
    	}
    }
    

      

    M. ACPC Headquarters : AASTMT (Stairway to Heaven)

    设$f[i][j]$表示志愿者$i$在第$j$天需要服务几个赛事,然后检查是否存在$j$满足$f[i][j]>1$即可。

    #include<iostream>
    #include<string>
    #include<map>
    using namespace std;
    int Case,n;
    string s;
    map<string,int>T;
    int m,f[10010][370];
    inline int getid(){
      cin>>s;
      int&t=T[s];
      if(t)return t;
      return t=++m;
    }
    inline void make(int x,int l,int r){
    	for(int i=l;i<=r;i++)f[x][i]++;
    }
    inline bool check(int x){
    	for(int i=1;i<=365;i++)if(f[x][i]>1)return 1;
    	return 0;
    }
    int main(){
      cin>>Case;
      while(Case--){
        cin>>n;
        T.clear();
        int ans=0;
        while(n--){
          cin>>s;
          int l,r,k;
          cin>>l>>r>>k;
          while(k--){
            int x=getid();
            make(x,l,r);
          }
        }
        for(map<string,int>::iterator it=T.begin();it!=T.end();it++){
          if(check(it->second))ans++;
        }
        cout<<ans<<endl;
        for(map<string,int>::iterator it=T.begin();it!=T.end();it++){
          if(check(it->second))cout<<it->first<<endl;
        }
        for(int i=1;i<=m;i++)for(int j=1;j<=365;j++)f[i][j]=0;
        m=0;
      }
      return 0;
    }
    

      


    总结:

    • D题_ilovelife对Claris提供的做法理解上出现了偏差,导致写了一个小时,还交了3发才通过。间接导致I题没有写完,以致没有AK。发生这种情况应考虑换人写。
    • E题poursoul在Claris写代码时进行误导,致使原来正确的公式被改成错误的公式,无故增加一发罚时,下次要注意。
  • 相关阅读:
    switch中局部变量的使用
    boost中regex的使用
    C++发送邮件jwsmpt
    c++编译相关
    一种处理多任务的线程池设计
    ICE的Timer和TimerTask
    bind2nd使用
    关于.NET WebSocket connection to 'ws://xxx' failed: Error during WebSocket handshake: Unexpected response code: 200
    QWrap Selector简介
    围观tangram
  • 原文地址:https://www.cnblogs.com/clrs97/p/5988357.html
Copyright © 2020-2023  润新知