2015 ACM/ICPC EC-Final

Claris發表於2016-12-05

A. Boxes and Balls

二分找到最大的不超過$n$的$\frac{x(x+1)}{2}$形式的數即可。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

void solve () {
	LL n ;
	scanf ( "%lld" , &n ) ;
	LL l = 1 , r = 2e9 ;
	while ( l < r ) {
		LL m = l + r + 1 >> 1 ;
		LL t = m * ( m + 1 ) / 2 ;
		if ( t <= n ) l = m ;
		else r = m - 1 ;
	}
	printf ( "%lld\n" , l * ( l + 1 ) / 2 ) ;
}


int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

B. Business Cycle

二分答案,然後暴力模擬,如果沒有爆負,則說明進入了迴圈節,後面直接算,注意最後要預留若干輪暴力模擬。

#include <bits/stdc++.h>
using namespace std ;

typedef long long ll ;

int n,i;
ll G,P,l,r,mid,ans,a[1111111];

bool check(ll have){
  if(have>=G)return 1;
  ll ret=P;
  ll old=-1;
  while(ret){
    ll st=have;
    bool flag=0;
    for(int i=0;i<n;i++){
      have+=a[i];
      if(have<0)flag=1,have=0;
      if(have>=G)return 1;
      ret--;
      if(!ret)return 0;
    }
    if(flag)continue;
    if(have<=st)return 0;
    old=have-st;
    break;
  }
  ll p=ret/n;
  p-=3;
  if(p<0)p=0;
  if(p>(G-have)/old)return 1;
  have+=p*old;
  ret-=p*n;
  if(have>=G)return 1;
  int i=0;
  while(ret--){
    have=max(0LL,have+a[i]);
    i++;
    i%=n;
    if(have>=G)return 1;
  }
  return 0;
}

void solve(){
  scanf("%d%lld%lld",&n,&G,&P);
  for(i=0;i<n;i++)scanf("%lld",&a[i]);
  l=0,r=G-1,ans=G;
  while(l<=r){
    if(check(mid=(l+r)>>1))r=(ans=mid)-1;else l=mid+1;
  }
  printf("%lld\n",ans);
}


int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

C. Suffixes and Palindromes

根據Manacher演算法可以得到$O(n)$對相等和不等關係,然後按照$sa$陣列逐個構造。

首先$sa[1]$必然填$'a'$,然後對於$sa[i]$,首先通過$rank$陣列判斷它能否和$sa[i-1]$相等,如果它可以相等,但是因為不等關係矛盾,那麼它只能大於$sa[i-1]$。

如此可以在$O(n)$時間內構造字典序最小的一組解,注意無解的處理。

#include <bits/stdc++.h>
using namespace std ;

typedef long long ll ;

const int N=1000110;

int n,m,i,j,r,p,f[N];
char a[N],s[N];

int len[N],e[N],fa[N],g[N],G[N],v[N],nxt[N],ed;
int sa[N],rk[N],col[N];

void NIE(){
  puts("Wrong calculation!");
}

inline void addedge(int x,int y){
  v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
}
inline void addedge2(int x,int y){
  v[++ed]=y;nxt[ed]=G[x];G[x]=ed;
}

int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}

inline bool makesame(int x,int y){
  if(x<0||y>m)return 0;
  if(x==y)return 1;
  if(x==0||y==m)return 0;
  if(x%2!=y%2)return 0;
  if(x%2==1)return 1;
  x>>=1;
  y>>=1;
  if(F(x)!=F(y))fa[fa[x]]=fa[y];
  //printf("same %d %d\n",x,y);
  return 1;
}

inline bool makediff(int x,int y){
  if(x==y)return 0;
  if(x<0||y>m)return 1;
  if(x==0||y==m)return 1;
  if(x%2!=y%2)return 1;
  if(x%2==1)return 0;
  x>>=1;
  y>>=1;
  addedge(x,y);
  addedge(y,x);
  //printf("diff %d %d\n",x,y);
  return 1;
}
inline bool bigger(int x,int y){//suffix[x] > suffix[y]?
  if(x>n)return 0;
  if(y>n)return 1;
  return rk[x]>rk[y];
}

void solve(){
  scanf("%d",&n);
  //scanf("%s",a+1);
  //for(i=1;i<=n;i++)s[i<<1]=a[i],s[i<<1|1]='#';
  s[0]='$';
  s[1]='#';
  s[m=(n+1)<<1]='@';
  /*for(r=p=0,f[1]=1,i=2;i<m;i++){
    for(f[i]=r>i?min(r-i,f[p*2-i]):1;s[i-f[i]]==s[i+f[i]];f[i]++);
    if(i+f[i]>r)r=i+f[i],p=i;
  }
  for(i=1;i<=m;i++)putchar(s[i]);puts("");
  for(i=1;i<=m;i++)printf("%d",f[i]);puts("");
  */
  for(i=1;i<=n;i++)scanf("%d",&sa[i]),sa[i]++;
  for(i=1;i<=n*2-1;i++){
    scanf("%d",&len[i]);
  }
  for(i=1;i<=n*2-1;i++){
    if(i&1){
      if(len[i]%2==0){
        NIE();
        return;
      }
    }else{
      if(len[i]%2){
        NIE();
        return;
      }
    }
    e[i+1]=len[i]+1;
  }
  e[1]=1;
  e[m-1]=e[m]=1;
  
  
  for(i=1;i<=n;i++)fa[i]=i;
  for(ed=0,i=1;i<=n;i++)g[i]=G[i]=0;
  
  for(r=p=0,f[1]=1,i=2;i<m;i++){
    for(f[i]=r>i?min(r-i,f[p*2-i]):1;f[i]<e[i];f[i]++){
      int x=i-f[i],y=i+f[i];
      if(!makesame(x,y)){
        NIE();
        return;
      }
    }
    if(f[i]!=e[i]){
      NIE();
      return;
    }
    int x=i-f[i],y=i+f[i];
    if(!makediff(x,y)){
      NIE();
      return;
    }
    if(i+f[i]>r)r=i+f[i],p=i;
  }
  
  for(i=1;i<=n;i++)F(i);
  for(i=1;i<=n;i++)for(j=g[i];j;j=nxt[j]){
    if(fa[i]==fa[v[j]]){
      NIE();
      return;
    }
    addedge2(fa[i],fa[v[j]]);
  }
  
  for(i=1;i<=n;i++)rk[sa[i]]=i;
  for(i=1;i<=n;i++)col[i]=0;
  col[fa[sa[1]]]=1;
  for(i=2;i<=n;i++){
    int x=sa[i];
    bool cansame=1;
    if(bigger(sa[i-1]+1,x+1))cansame=0;
    //printf("%d %d\n",i,cansame);
    int pre=col[fa[sa[i-1]]];
    if(col[fa[x]]){
      if(cansame){
        if(col[fa[x]]<pre){
          NIE();
          return;
        }
      }else{
        if(col[fa[x]]<=pre){
          NIE();
          return;
        }
      }
      continue;
    }
    for(j=G[fa[x]];j;j=nxt[j])if(col[v[j]]==pre)cansame=0;
    if(!cansame)pre++;
    if(pre>26){
      NIE();
      return;
    }
    col[fa[x]]=pre;
  }
  for(i=1;i<=n;i++)putchar('a'+col[fa[i]]-1);
  puts("");
}



int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

D. Change

分類討論即可。

#include <bits/stdc++.h>
using namespace std ;

void solve () {
	double x , y ;
	scanf ( "%lf%lf" , &x , &y ) ;
	int a = x * 100 + 0.5 ;
	int b = y * 100 + 0.5 ;
	if ( b == 1 || b == 10 || b == 100 || b == 1000 || b == 10000 ) {
		if ( a == 2 * b ) printf ( "0.01\n" ) ;
		else printf ( "0.02\n" ) ;
	} else printf ( "0.01\n" ) ;
}

int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

E. Colorful Floor

留坑。

 

F. Hungry Game of Ants

DP出每隻螞蟻往左往右吃完的方案數,用字首和優化即可。時間複雜度$O(n)$。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

const int MAXN = 1000005 ;
const int mod = 1e9 + 7 ;

LL dp[MAXN] , f[MAXN] , sum[MAXN] ;
int n , k ;

void up ( LL& x , LL y ) {
	x += y ;
	if ( x >= mod ) x -= mod ;
}

void solve () {
	scanf ( "%d%d" , &n , &k ) ;
	if ( k == 1 ) {
		printf ( "0\n" ) ;
		return ;
	}
	for ( int i = 0 ; i <= n ; ++ i ) {
		dp[i] = f[i] = 0 ;
		if ( i ) sum[i] = sum[i - 1] + i ;
	}
	LL ans = 2 , p = 1 ;
	for ( int i = 2 ; i < k ; ++ i ) {
		up ( p , p ) ;
		if ( sum[i] < sum[k] - sum[i] ) up ( ans , p ) ;
	}
	if ( k == n ) {
		printf ( "%lld\n" , ans * 2 % mod ) ;
		return ;
	}
	dp[k] = f[k] = ans ;
	for ( int i = 1 , j = 1 ; i <= n ; ++ i ) {
		while ( sum[i] > 2 * sum[j] ) ++ j ;
		up ( dp[i] , ( f[i - 1] - f[j - 1] + mod ) % mod ) ;
		up ( f[i] , ( f[i - 1] + dp[i] ) % mod ) ;
	}
	printf ( "%lld\n" , dp[n] ) ;
}

int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

G. Legacy of the Void

留坑。

 

H. Open Face Chinese Poker

留坑。

 

I. Champions League

留坑。

 

J. Dome and Steles

二分答案,然後解出每個磚塊能放的範圍,按範圍從大到小放,每次貪心放大的那一側即可。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

const int Maxn = 100005 ;
const double eps=1e-10;
double a[Maxn],ned[Maxn];
int n;
double sqr(double x){return x*x;}
int dcmp(double x){if(fabs(x)<eps)return 0;if(x>eps)return 1;return -1;}
bool check(double md){
	for(int i=0;i<n;i++){
		if(dcmp(md*md-a[i])<=0)return 0;
	}
	//for(int i=0;i<n;i++)printf("%.3f ",ned[i]);puts("");
	double l=md,r=md;
	for(int i=0;i<n;i++){
		if(l<r)swap(l,r);
		l=min(l,sqrt(md*md-a[i]));
		if(dcmp(l-1)>=0){l-=1;continue;}
		else{
			if(dcmp(l+r-1)<0)return 0;
			if((1-l)*(1-l)+a[i]>md*md)return 0;
			if(i!=(n-1))return 0;
		}
	}
	return 1;
}
void solve () {
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		double x,y;
		scanf("%lf%lf",&x,&y);
		a[i]=min(sqr(x)+sqr(y/2),sqr(y)+sqr(x/2));
	}
	sort(a,a+n);
	double l=0,r=1e6;
	for(int i=0;i<200;i++){
		double md=(l+r)/2;
		if(check(md))r=md;
		else l=md;
	}
	printf("%.12f\n",r);
	
}

int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

K. Convex Polyhedron

求出三維凸包之後,假如知道了投影方向向量,那麼根據叉積的正負號貪心把所有正的法向量加起來即可。於是隨機列舉10000個方向向量即可。

#include <bits/stdc++.h>
using namespace std ;

#define PR 1e-8 
#define N 620

struct TPoint {
	double x , y , z ;
	TPoint () {}
	TPoint ( double x , double y , double z ) : x ( x ) , y ( y ) , z ( z ) {}
	TPoint operator+(const TPoint p){return TPoint(x+p.x,y+p.y,z+p.z);}
	TPoint operator-(const TPoint p){return TPoint(x-p.x,y-p.y,z-p.z);}
	TPoint operator*(const TPoint p){
		return TPoint(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);
	}
	TPoint operator*(double p){return TPoint(x*p,y*p,z*p);}
	TPoint operator/(double p){return TPoint(x/p,y/p,z/p);}
	double operator^(const TPoint p){return x * p.x + y * p.y + z * p.z ;}
	void show (){
		printf ( "%.2f %.2f %.2f\n" , x , y , z ) ;
	}
}center;

struct fac{
	int a , b , c ;
	bool ok ;
} ;

struct T3dhull{
	int n ;
	TPoint ply[N];
	int trianglecnt;
	fac tri[N] ;
	int vis[N][N];
	double dist(TPoint a ) {
		return sqrt ( a.x * a.x + a.y * a.y + a.z * a.z ) ;
	}
	double area( TPoint a , TPoint b , TPoint c ) {
		return dist ( ( b - a ) * ( c - a ) ) ;
	}
	TPoint fa(TPoint a,TPoint b,TPoint c){
		return (b-a)*(c-a);
	}
	double volume ( TPoint a , TPoint b , TPoint c , TPoint d ) {
		return ( b - a ) * ( c - a ) ^ ( d - a ) ;
	}
	double ptoplane ( TPoint &p , fac& f ) {
		TPoint m = ply[f.b]-ply[f.a],n=ply[f.c]-ply[f.a],t=p-ply[f.a];
		return (m*n)^t;
	}
	void deal(int p,int a,int b ){
		int f = vis[a][b];
		fac add;
		if(tri[f].ok){
			if((ptoplane(ply[p],tri[f]))>PR)dfs(p,f);else{
				add.a=b,add.b=a,add.c=p,add.ok=1;
				vis[p][b]=vis[a][p]=vis[b][a]=trianglecnt;
				tri[trianglecnt++]=add;
			}
		}
	}
	void dfs(int p,int cnt ) {
		tri[cnt].ok = 0 ;
		deal(p,tri[cnt].b,tri[cnt].a);
		deal(p,tri[cnt].c,tri[cnt].b);
		deal(p,tri[cnt].a,tri[cnt].c);
	}
	bool same ( int s , int e ) {
		TPoint a = ply[tri[s].a],b=ply[tri[s].b],c=ply[tri[s].c];
		return fabs ( volume(a , b , c , ply[tri[e].a] ) ) < PR
		&& fabs( volume(a , b , c , ply[tri[e].b]))<PR
		&& fabs( volume(a , b  ,c , ply[tri[e].c]))<PR;
	}
	void construct(){
		int i,j;
		trianglecnt=0;
		if ( n < 4 ) return ;
		bool tmp = 1 ;
		for ( i = 1 ; i < n ; ++ i ) {
			if ( ( dist(ply[0]-ply[i]))>PR){
				swap ( ply[1],ply[i]);
				tmp=0;
				break ;
			}
		}
		if ( tmp ) return ;
		tmp = 1 ;
		for ( i = 2 ; i < n ; ++ i ) {
			if ( ( dist((ply[0]-ply[1])*(ply[1]-ply[i])))>PR){
				swap ( ply[2],ply[i]);
				tmp=0;
				break;
			}
		}
		if(tmp)return;
		tmp=1;
		for(i=3;i<n;++i){
			if(fabs((ply[0]-ply[1])*(ply[1]-ply[2])^(ply[0]-ply[i]))>PR){
				swap(ply[3],ply[i]);
				tmp=0;
				break;
			}
		}
		if(tmp)return;
		tmp=1;
		fac add;
		for(i=0;i<4;++i){
			add.a=(i+1)%4,add.b=(i+2)%4,add.c=(i+3)%4,add.ok=1;
			if((ptoplane(ply[i],add))>0)swap(add.b,add.c);
			vis[add.a][add.b]=vis[add.b][add.c]=vis[add.c][add.a]=trianglecnt;
			tri[trianglecnt++]=add;
		}
		for(i=4;i<n;++i){
			for(j=0;j<trianglecnt;++j){
				if(tri[j].ok&&(ptoplane(ply[i],tri[j]))>PR){
					dfs(i,j);
					break;
				}
			}
		}
		int cnt = trianglecnt;
		trianglecnt=0;
		for(i=0;i<cnt;++i){
			if(tri[i].ok){
				tri[trianglecnt++]=tri[i];
			}
		}
	}
	void show(){
		for ( int i = 0 ; i < trianglecnt;++i){
			printf ( "------%d------\n" , i ) ;
			ply[tri[i].a].show () ;
			ply[tri[i].b].show () ;
			ply[tri[i].c].show () ;
		}
	}
	double check(TPoint mydi){
		TPoint ret=TPoint(.0,.0,.0);
		for(int i=0;i<trianglecnt;i++){
			TPoint cur=fa(ply[tri[i].a],ply[tri[i].b],ply[tri[i].c]);
			if((mydi^cur)>=0)ret=ret+cur;
		}
		return dist(ret);
	}
	int getrand(){
		int ret=rand()%200;
		if(rand()%2)ret=-ret;
		return ret;
	}
	void solve(){
		double ans=0;
		for(int i=0;i<10000;i++){
			TPoint mydi;
			mydi.x=getrand();
			mydi.y=getrand();
			mydi.z=getrand();
			ans=max(ans,check(mydi));
		}
		printf("%.12f\n",ans/2);
	}
} a;

void solve () {
	scanf ( "%d",&a.n);
	for ( int i = 0 ; i < a.n ; ++ i ) {
		scanf ( "%lf%lf%lf" , &a.ply[i].x,&a.ply[i].y,&a.ply[i].z);
	}
	a.construct();
	//a.show();
	a.solve();
}

int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

L. Multiplication Table

列舉約數然後檢驗。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

int n,m;
int a[1020][1020];
struct Node{
	int x,y,z;
	Node(){}
	Node(int x,int y,int z):x(x),y(y),z(z){}
}nd[1000020];
int cnt;
int csx,csy;
bool check(int ox,int oy,int rx,int ry){
	if(rx-(ox-1)<1)return 0;
	if(ry-(oy-1)<1)return 0;
	for(int i=0;i<cnt;i++){
		int x=nd[i].x,y=nd[i].y,z=nd[i].z;
		if(1LL*(rx+(x-ox))*(ry+(y-oy))!=z)return 0;
	}
	return 1;
}
void solve () {
	scanf("%d%d",&n,&m);
	cnt=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char s[20];
			scanf("%s",s);
			if(s[0]=='?')continue;
			int x=0;
			for(int k=0;s[k];k++){
				x=x*10+s[k]-'0';
			}
			nd[cnt++]=Node(i,j,x);
		}
	}
	if(!cnt){puts("Yes");return;}
	bool flag=0;
	int num=nd[0].z;
	csx=nd[0].x,csy=nd[0].y;
	for(int i=1;i<cnt;i++){
		if(num>nd[i].z){
			num=nd[i].z;
			csx=nd[i].x;
			csy=nd[i].y;
		}
	}
	for(int i=1;i<=num/i&&!flag;i++){
		if(num%i==0){
			if(check(csx,csy,i,num/i)){flag=1;break;}
			if(i*i!=num&&check(csx,csy,num/i,i)){flag=1;break;}
		}
	}
	puts(flag?"Yes":"No");
}


int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  

M. November 11th

對於長度為$n$的長條,對最小值的貢獻為$\lfloor\frac{n+1}{2}\rfloor$,對最大值的貢獻為$\lfloor\frac{n+2}{3}\rfloor$。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

int n,m,i,j,k,x,y,f[1111][1111],ans0,ans1;
inline int F(int n){
  return (n+1)/2;
}
inline int G(int n){
  if(n==1)return 1;
  return (n+2)/3;
}
void solve () {
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)f[i][j]=1;
	scanf("%d",&k);
	while(k--)scanf("%d%d",&x,&y),f[x+1][y+1]=0;
	ans0=ans1=0;
	for(i=1;i<=n;i++){
	  j=1;
	  for(;j<=m;){
	    if(!f[i][j]){j++;continue;}
	    for(k=j;k<=m&&f[i][k];k++);
	    ans0+=F(k-j);
	    ans1+=G(k-j);
	    j=k;
          }
        }
        printf("%d %d\n",ans0,ans1);
}


int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		printf ( "Case #%d: " , i ) ;
		solve () ;
	}
	return 0 ;
}

  


總結:

  • B題忘記考慮預留的情況,導致WA5發。
  • C題對無解的判斷不足以及陣列開少一半,導致WA。
  • M題沒有想清楚,導致WA。

 

相關文章