2015 ACM/ICPC EC-Final

时间:2023-01-24 11:00:53

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。