组队练习 2011年福州全国邀请赛
A 水题。
B 计算几何求重心,枚举对称点。
#include <string.h> #include <algorithm> #include <stdio.h> #include <cmath> #include <iostream> using namespace std; #define maxn 600 #define eps 1e-6 bool zero(double a) {return (fabs(a)<eps?1:0);} struct point{ double x,y; }po[maxn],center; int n; struct line{ point a,b; }; double cross1(point &a,point &b,point &c){ return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); } double cross(point p1,point p2,point p0){ return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); } point intersection(line u,line v){ point ret=u.a; double t=((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))/((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x)); ret.x+=(u.b.x-u.a.x)*t; ret.y+=(u.b.y-u.a.y)*t; return ret; } point barycenter(point a,point b,point c){ line u,v; u.a.x=(a.x+b.x)/2; u.a.y=(a.y+b.y)/2; u.b=c; v.a.x=(a.x+c.x)/2; v.a.y=(a.y+c.y)/2; v.b=b; return intersection(u,v); } point barycenter(int n,point *p){ point ret,t; double t1=0,t2; int i; ret.x=ret.y=0; for(i=1;i<n-1;i++){ if(fabs(t2=cross(p[0],p[i],p[i+1]))>eps){ t=barycenter(p[0],p[i],p[i+1]); ret.x+=t.x*t2; ret.y+=t.y*t2; t1+=t2; } } if(fabs(t1)>eps) ret.x/=t1,ret.y/=t1; return ret; } double dmult(point &a,point &b){ return a.x*b.x+a.y*b.y; } double dmult(double a,double b,double c,double d){ return a*c+b*d; } bool is_ok(int l,int r,int a,int b){ if(r<l)return true; point temp,t; while(l<r){ temp.x=(po[l].x+po[r].x)/2; temp.y=(po[l].y+po[r].y)/2; if(!zero(dmult(po[l].x-po[r].x,po[l].y-po[r].y,temp.x-center.x,temp.y-center.y))) return false; l++,r--; } temp.x=(po[a].x+po[b].x)/2; temp.y=(po[a].y+po[b].y)/2; if(l==r) return zero(cross(temp,center,po[l])); return true; } bool sovle(){ int i,k; point temp; for(i=1;i<n;i++){ temp.x=(po[0].x+po[i].x)/2; temp.y=(po[0].y+po[i].y)/2; if(zero(dmult(po[i].x-po[0].x,po[i].y-po[0].y,temp.x-center.x,temp.y-center.y))){ if(is_ok(1,i-1,0,i)&& is_ok(i+1,n-1,0,i)) return true; } } for(i=2;i<n;i++){ temp.x=(po[1].x+po[i].x)/2; temp.y=(po[1].y+po[i].y)/2; if(zero(dmult(po[i].x-po[1].x,po[i].y-po[1].y,temp.x-center.x,temp.y-center.y))){ //printf("HHHH%lf %lf\n",po[i].x,po[i].y); if(is_ok(2,i-1,1,i)&& is_ok(i+1,n,1,i)) return true; } } return false; } int main(){ int i,j,k,t,cas=0; scanf("%d",&t); while(t--){ scanf("%d",&n); for(i=0;i<n;i++) scanf("%lf%lf",&po[i].x,&po[i].y); k=1; for(i=2;i<n;i++){ if(zero(cross(po[k-1],po[k],po[i]))) po[k]=po[i]; else po[++k]=po[i]; } k++; if(zero(cross(po[0],po[k-1],po[k-2]))) k--; if(zero(cross(po[k-1],po[0],po[1]))){ for(i=1;i<k;i++) po[i-1]=po[i]; k--; } n=k; printf("Case %d: ",++cas); if(k<=2){ printf("YES\n"); continue; } po[n]=po[0]; center=barycenter(n,po); if(sovle()) printf("YES\n"); else printf("NO\n"); } return 0; }
C 数学题。
import java.math.*; import java.math.BigDecimal; import java.util.*; public class Main { public static void main(String arg[]){ BigDecimal a,b,c,x,y,z,d,an,ans; Scanner cin=new Scanner(System.in); int t=1,tt; tt=cin.nextInt(); an=BigDecimal.valueOf(32); while(tt-->0){ a=cin.nextBigDecimal(); b=cin.nextBigDecimal(); if(a.compareTo(b)>0){ c=a.subtract(b); d=b; ans=a; }else{ c=b.subtract(a); d=a; ans=b; } if(c.compareTo(an)<0){ double s=c.doubleValue(); s=Math.pow(2.0,s)+1; s=Math.log(s)/Math.log(2.0); ans=d; ans=ans.add(BigDecimal.valueOf(s)); } ans = ans.setScale(9, BigDecimal.ROUND_HALF_UP); System.out.println("Case "+t+": "+ans); t++; } } }
D 数学
#include<iostream> #include<cmath> #include<cstring> #include<string> #include<algorithm> #include<iomanip> #include<cstdio> #define ll long long #define M 1000001 #define mod 1000000007 using namespace std; ll an[M]; double p[M]; void init() { an[0]=0;an[1]=1; p[0]=0;p[1]=1; ll t=1; for(int i=2;i<M;i++){ an[i]=(i*an[i-1]%mod+t)%mod; t=(t*i)%mod; p[i]=p[i-1]+1.0/(double)i; } } int main() { int t,n,ca=0; init(); scanf("%d",&t); while(t--){ scanf("%d",&n); printf("Case %d: %I64d %.6lf\n",++ca,an[n],p[n]); } return 0; }
E 树形DP。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define Maxn 100010 #define LL __int64 using namespace std; int son[Maxn],vi[Maxn],head[Maxn],e; struct Edge{ int u,v,next; LL val; }edge[Maxn*3]; LL ans,sum; void add(int u,int v,LL val) { edge[e].u=u,edge[e].v=v,edge[e].val=val,edge[e].next=head[u],head[u]=e++; edge[e].u=v,edge[e].v=u,edge[e].val=val,edge[e].next=head[v],head[v]=e++; } void init() { memset(son,0,sizeof(son)); memset(vi,0,sizeof(vi)); memset(head,-1,sizeof(head)); e=0; } void dfs(int u) { int i,v; son[u]=1; vi[u]=1; for(i=head[u];i!=-1;i=edge[i].next){ v=edge[i].v; //cout<<u<<" "<<v<<" "; if(vi[v]) continue; dfs(v); //cout<<son[v]<<" "<<sum<<" "<<edge[i].val<<endl; ans+=son[v]*(sum-son[v])*2*edge[i].val; son[u]+=son[v]; } } int main() { int t,n,a,b,i,j,Ca=0; LL c; scanf("%d",&t); while(t--){ init(); scanf("%d",&n); for(i=1;i<n;i++){ scanf("%d%d%I64d",&a,&b,&c); a++,b++; add(a,b,c); } ans=0; sum=n; dfs(1); printf("Case %d: %I64d\n",++Ca,ans); } return 0; }
F 是个最大匹配
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #define Maxn 110 using namespace std; int match[Maxn],n,m; bool g[Maxn][Maxn],vi[Maxn]; int dfs(int u) { int i; for(i=1;i<=m;i++){ if(!vi[i]&&g[u][i]){ vi[i]=1; if(match[i]==-1||dfs(match[i])){ match[i]=u; return true; } } } return false; } int main() { int t,e,i,j,u,v,Ca=0; scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&e); memset(g,1,sizeof(g)); for(i=1;i<=e;i++){ scanf("%d%d",&u,&v); g[u][v]=0; } memset(match,-1,sizeof(match)); int ans=0; for(i=1;i<=n;i++){ memset(vi,0,sizeof(vi)); if(dfs(i)) ans++; } printf("Case %d: %d\n",++Ca,ans); } return 0; }
先O(n)预处理出ri[i][j],le[i][j],分别表示第i个位置向右边移动出j个空格需要的步数,表示第i个位置向左边移动出j个空格需要的步数。
然后枚举间隙处,二分判段最大间隔。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define Maxn 710 #define inf 100000000 using namespace std; int ri[Maxn][Maxn],le[Maxn][Maxn],n,m; char str[Maxn]; bool OK(int pos,int x) { int i,j,cnt=inf; if(pos==1) { cnt=min(cnt,ri[pos][x]); return cnt<=m; } for(i=0;i<=n;i++){ if(i>x) break; cnt=min(cnt,ri[pos][i]+le[pos-1][x-i]); } //cout<<pos<<" "<<x<<" "<<cnt<<" "<<m<<endl; return cnt<=m; } int main() { int t,i,j,ze,Ca=0; scanf("%d",&t); while(t--){ for(i=1;i<Maxn;i++){ for(j=1;j<Maxn;j++){ ri[i][j]=le[i][j]=inf; } } ze=0; scanf("%d%d%s",&n,&m,str); if(str[0]=='0') le[1][1]=0,ze=1; for(i=1;i<n;i++){ if(str[i]=='0') ze++; for(j=1;j<=n;j++){ if(le[i][j-1]>=inf) break; if(str[i]=='1') le[i+1][j]=le[i][j]+j; else le[i+1][j]=le[i][j-1]; } } if(str[n-1]=='0') ri[n][1]=ri[n+1][1]=0; for(i=n-1;i>=1;i--){ for(j=1;j<=n;j++){ if(ri[i+1][j-1]>=inf) break; if(str[i-1]=='1') ri[i][j]=ri[i+1][j]+j; else ri[i][j]=ri[i+1][j-1]; } } int f=0; int ans=0,l,r,mid; for(i=1;i<=n;i++){ if(str[i-1]=='0'){ l=0;r=ze; while(l+1<r){ mid=(l+r)>>1; if(OK(i,mid)) l=mid; else r=mid; } ans=max(ans,l); if(OK(i,r)) ans=max(ans,r); } } printf("Case %d: %d\n",++Ca,ans); } return 0; }