nenu contest2
http://vjudge.net/vjudge/contest/view.action?cid=54562#overview
H B. Polygons http://codeforces.com/problemset/problem/166/B
目前已知两种解法,先贴一个凸包的。算法是把两个多边形的点一起做一个凸包,看这个凸包是否包含b的点,包含说明b不是严格在a内,凸包要包括边上的点。复杂度nlogn,n为两个凸包点的和n=m+n=120000。nlogn=2024720。
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 const double eps=1e-8; 6 const int M=200010; 7 struct point{ 8 double x,y; 9 bool type; 10 }a[M],b[M]; 11 bool operator < (const point &l, const point &r) { 12 return l.y < r.y || (fabs(l.y- r.y)<eps && l.x < r.x); 13 } 14 class ConvexHull { //凸包 15 bool mult(point sp, point ep, point op) {//>包括凸包边上的点,>=不包括 16 return (sp.x - op.x) * (ep.y - op.y)> (ep.x - op.x) * (sp.y - op.y); 17 } 18 public: 19 int graham(int n,point p[],point res[]) {//多边形点个数和点数组,凸包存res 20 sort(p, p + n); 21 if (n == 0) return 0; 22 res[0] = p[0]; 23 if (n == 1) return 1; 24 res[1] = p[1]; 25 if (n == 2) return 2; 26 res[2] = p[2]; 27 int top=1; 28 for (int i = 2; i < n; i++) { 29 while (top && mult(p[i], res[top], res[top-1])) top--; 30 res[++top] = p[i]; 31 } 32 int len = top; 33 res[++top] = p[n - 2]; 34 for (int i = n - 3; i >= 0; i--) { 35 while (top!=len && mult(p[i], res[top],res[top-1])) top--; 36 res[++top] = p[i]; 37 } 38 return top; // 返回凸包中点的个数 39 } 40 } gx; 41 int main(){ 42 int n,m; 43 while(~scanf("%d",&n)){ 44 for(int i=0;i<n;i++){ 45 scanf("%lf%lf",&a[i].x,&a[i].y); 46 a[i].type=true; 47 } 48 scanf("%d",&m); 49 for(int i=0;i<m;i++){ 50 scanf("%lf%lf",&a[i+n].x,&a[i+n].y); 51 a[i+n].type=false; 52 } 53 int lb=gx.graham(n+m,a,b); 54 bool flag=true; 55 for(int i=0;i<lb;i++){ 56 if(!b[i].type){ 57 flag=false; 58 break; 59 } 60 } 61 if(flag) puts("YES"); 62 else puts("NO"); 63 } 64 return 0; 65 }
还有就是直接on判断b的点是否在a内。复杂度mlogn,m是b的点,n是a的点。mlogn=332192.
1 #include<cstdio> 2 const int M=100010; 3 struct point{ 4 double x,y; 5 }a[M],p; 6 class PinConvexHull{//判断点严格在凸包内(logn) 7 double mult(point sp,point ep,point op){ 8 return (sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y); 9 } 10 public: 11 bool solve(point p,point a[],int n){//传入待判断点,凸包点数组,凸包点个数 12 int L=1,R=n-1; 13 while(L<=R){ 14 int mid=(L+R)>>1; 15 if(mult(a[mid],p,a[0])>=0){ 16 R=mid-1; 17 } 18 else{ 19 L=mid+1; 20 } 21 } 22 if(L<2||mult(a[n-1],p,a[0])<=0||mult(a[L-1],p,a[L])<=0) { 23 return false; 24 } 25 return true; 26 } 27 }gx; 28 int main(){ 29 int n,m; 30 while(~scanf("%d",&n)){ 31 for(int i=0;i<n;i++){ 32 scanf("%lf%lf",&a[i].x,&a[i].y); 33 } 34 scanf("%d",&m); 35 bool flag=true; 36 while(m--){ 37 scanf("%lf%lf",&p.x,&p.y); 38 if(!gx.solve(p,a,n)) flag=false; 39 } 40 if(flag) puts("YES"); 41 else puts("NO"); 42 } 43 return 0; 44 }
F Minimal Ratio Tree http://acm.hdu.edu.cn/showproblem.php?pid=2489
最小生成树克鲁斯卡尔,二进制枚举,浮点数比较加eps,输出格式不要多余空格,边的数组大小要注意,最大能n^2
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 #define mt(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 const double eps=1e-8; 8 const int inf=0x7fffffff; 9 const int M=512; 10 class Kruskal { //最小生成树 kruskal 算法 11 class UnionFindSet {//并查集 12 int par[M]; 13 public: 14 void init() { 15 mt(par,-1); 16 } 17 int getroot(int x) { 18 int i=x,j=x,temp; 19 while(par[i]>=0) i=par[i]; 20 while(j!=i) { 21 temp=par[j]; 22 par[j]=i; 23 j=temp; 24 } 25 return i; 26 } 27 bool unite(int x,int y) { 28 int p=getroot(x); 29 int q=getroot(y); 30 if(p==q)return false; 31 if(par[p]>par[q]) { 32 par[q]+=par[p]; 33 par[p]=q; 34 } else { 35 par[p]+=par[q]; 36 par[q]=p; 37 } 38 return true; 39 } 40 } f; 41 struct E { 42 int u,v,w; 43 friend bool operator < (E a,E b) { 44 return a.w<b.w; 45 } 46 } e[M]; 47 int le,res,num,n; 48 public: 49 void init(int x) { 50 n=x; 51 le=res=0; 52 f.init(); 53 num=1; 54 } 55 void add(int u,int v,int w) { 56 e[le].u=u; 57 e[le].v=v; 58 e[le].w=w; 59 le++; 60 } 61 void solve() { 62 sort(e,e+le); 63 for(int i=0; i<le&&num<n; i++) { 64 if(f.unite(e[i].u,e[i].v)) { 65 num++; 66 res+=e[i].w; 67 } 68 } 69 if(num<n) res=inf; 70 } 71 int getvalue() { 72 return res; 73 } 74 }gx; 75 int one(int x){ 76 int res=0; 77 while(x){ 78 if(x&1){ 79 res++; 80 } 81 x>>=1; 82 } 83 return res; 84 } 85 int val[M],tmp[M],ans[M],dist[M][M]; 86 int main(){ 87 int n,m; 88 while(~scanf("%d%d",&n,&m),n|m){ 89 for(int i=0;i<n;i++){ 90 scanf("%d",&val[i]); 91 } 92 for(int i=0;i<n;i++){ 93 for(int j=0;j<n;j++){ 94 scanf("%d",&dist[i][j]); 95 } 96 } 97 int big=1<<n; 98 double sma=inf; 99 for(int i=0;i<big;i++){ 100 if(one(i)==m){ 101 int lt=0; 102 int sumnode=0; 103 for(int j=0;j<n;j++){ 104 if((i>>j)&1){ 105 tmp[lt++]=j; 106 sumnode+=val[j]; 107 } 108 } 109 gx.init(m); 110 for(int j=0;j<m;j++){ 111 for(int k=j+1;k<m;k++){ 112 gx.add(j,k,dist[tmp[j]][tmp[k]]); 113 } 114 } 115 gx.solve(); 116 int sumedge=gx.getvalue(); 117 double now=sumedge*1.0/sumnode; 118 if(sma>now+eps){ 119 sma=now; 120 for(int j=0;j<m;j++){ 121 ans[j]=tmp[j]; 122 } 123 continue; 124 } 125 if(fabs(sma-now)<eps){ 126 bool flag=false; 127 for(int j=0;j<m;j++){ 128 if(tmp[j]>ans[j]) break; 129 if(tmp[j]<ans[j]){ 130 flag=true; 131 break; 132 } 133 } 134 if(flag){ 135 for(int j=0;j<m;j++){ 136 ans[j]=tmp[j]; 137 } 138 } 139 } 140 } 141 } 142 for(int i=0;i<m;i++){ 143 if(i) printf(" "); 144 printf("%d",ans[i]+1); 145 } 146 puts(""); 147 } 148 return 0; 149 }
最小生成树prim,一样一样的。
1 #include<cstdio> 2 #include<cmath> 3 const double eps=1e-8; 4 const int inf=0x7fffffff; 5 const int M=32; 6 class Prim { //无向图最小生成树 prim,邻接阵O(n^2)必须保证图的连通的! 7 int n,mat[M][M],dis[M],pre[M],v[M],ret,i,j,k; 8 public: // pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1 9 void init(int x) { 10 n=x; 11 for(i=0; i<n; i++) 12 for(j=0; j<n; j++) 13 mat[i][j]=i==j?0:inf;//不相邻点边权inf 14 } 15 void add(int u,int v,int w) { 16 mat[u][v]=w; 17 mat[v][u]=w; 18 } 19 int solve() { 20 ret=0; 21 for (i=0; i<n; i++) dis[i]=inf,v[i]=0,pre[i]=-1; 22 for (dis[j=0]=0; j<n; j++) { 23 for (k=-1,i=0; i<n; i++) if (!v[i]&&(k==-1||dis[i]<dis[k])) k=i; 24 for (v[k]=1,ret+=dis[k],i=0; i<n; i++) if (!v[i]&&mat[k][i]<dis[i]) dis[i]=mat[pre[i]=k][i]; 25 } 26 return ret;//返回最小生成树的长度 27 } 28 }gx; 29 int val[M],tmp[M],ans[M],dist[M][M]; 30 int one(int x){ 31 int res=0; 32 while(x){ 33 if(x&1){ 34 res++; 35 } 36 x>>=1; 37 } 38 return res; 39 } 40 int main(){ 41 int n,m; 42 while(~scanf("%d%d",&n,&m),n|m){ 43 for(int i=0;i<n;i++){ 44 scanf("%d",&val[i]); 45 } 46 for(int i=0;i<n;i++){ 47 for(int j=0;j<n;j++){ 48 scanf("%d",&dist[i][j]); 49 } 50 } 51 int big=1<<n; 52 double sma=inf; 53 for(int i=0;i<big;i++){ 54 if(one(i)==m){ 55 int lt=0,sumnode=0; 56 for(int j=0;j<n;j++){ 57 if((i>>j)&1){ 58 tmp[lt++]=j; 59 sumnode+=val[j]; 60 } 61 } 62 gx.init(m); 63 for(int j=0;j<m;j++){ 64 for(int k=j+1;k<m;k++){ 65 gx.add(j,k,dist[tmp[j]][tmp[k]]); 66 } 67 } 68 int sumedge=gx.solve(); 69 double now=sumedge*1.0/sumnode; 70 if(sma>now+eps){ 71 sma=now; 72 for(int j=0;j<m;j++){ 73 ans[j]=tmp[j]; 74 } 75 continue; 76 } 77 if(fabs(sma-now)<eps){ 78 bool flag=false; 79 for(int j=0;j<m;j++){ 80 if(tmp[j]>ans[j]) break; 81 if(tmp[j]<ans[j]){ 82 flag=true; 83 break; 84 } 85 } 86 if(flag){ 87 for(int j=0;j<m;j++){ 88 ans[j]=tmp[j]; 89 } 90 } 91 } 92 } 93 } 94 for(int i=0;i<m;i++){ 95 if(i) printf(" "); 96 printf("%d",ans[i]+1); 97 } 98 puts(""); 99 } 100 return 0; 101 }
G The area http://acm.hdu.edu.cn/showproblem.php?pid=1071
给3个点,两点确定一条直线,三点确定二次函数的方程,分别求区间内的面积,积分,然后相减就是阴影面积。
1 #include<cstdio> 2 int main() { 3 int t; 4 double x1,x2,x3,y1,y2,y3; 5 while(~scanf("%d",&t)) { 6 while(t--) { 7 scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3); 8 double a2=(y3-y2)/(x3-x2); 9 double b2=y2-a2*x2; 10 double a1=((y2-y1)/(x2-x1)-(y3-y1)/(x3-x1))/(x2-x3); 11 double b1=(y3-y1)/(x3-x1)-a1*(x3+x1); 12 double c1=y1-a1*x1*x1-b1*x1; 13 double s1=a1*x3*x3*x3/3+b1*x3*x3/2+c1*x3; 14 double h1=a1*x2*x2*x2/3+b1*x2*x2/2+c1*x2; 15 s1-=h1; 16 double s2=a2*x3*x3/2+b2*x3; 17 double h2=a2*x2*x2/2+b2*x2; 18 s2-=h2; 19 printf("%.2f\n",s1-s2); 20 } 21 } 22 return 0; 23 }
E Ping pong http://acm.hdu.edu.cn/showproblem.php?pid=2492
用on的预处理出某一个位置之前几个比它小,几个它大,后面同理,前面小乘后面大的个数,是一种,前面大乘后面小的,是一种。预处理中要快速知道前面有几个比我小,那么可以用树状数组把on的求和降到logn。
1 #include<cstdio> 2 #include<cstring> 3 #define mt(a,b) memset(a,b,sizeof(a)) 4 typedef __int64 LL; 5 const int M=100010; 6 class One_Tree_Array { //一维树状数组 7 typedef int typev; 8 typev a[M]; 9 public: 10 void init() { 11 mt(a,0); 12 } 13 int lowb(int t) { 14 return t&(-t); 15 } 16 void add(int i,typev v) { 17 for(; i<M; a[i]+=v,i+=lowb(i)); 18 } 19 typev sum(int i) { 20 typev s=0; 21 for(; i>0; s+=a[i],i-=lowb(i)); 22 return s; 23 } 24 }gx; 25 int a[M],big[M],sma[M],prebig[M],presma[M]; 26 int main(){ 27 int t,n; 28 while(~scanf("%d",&t)){ 29 while(t--){ 30 scanf("%d",&n); 31 for(int i=1;i<=n;i++){ 32 scanf("%d",&a[i]); 33 } 34 gx.init(); 35 for(int i=n;i>=1;i--){ 36 sma[i]=gx.sum(a[i]); 37 big[i]=n-i-sma[i]; 38 gx.add(a[i],1); 39 } 40 gx.init(); 41 for(int i=1;i<=n;i++){ 42 presma[i]=gx.sum(a[i]); 43 prebig[i]=i-1-presma[i]; 44 gx.add(a[i],1); 45 } 46 LL ans=0; 47 for(int i=1;i<=n;i++){ 48 ans+=prebig[i]*sma[i]; 49 ans+=presma[i]*big[i]; 50 } 51 printf("%I64d\n",ans); 52 } 53 } 54 return 0; 55 }
当然可以掏出线段树来做树状数组的工作。
1 #include<cstdio> 2 #include<cstring> 3 #define mt(a,b) memset(a,b,sizeof(a)) 4 #define lrrt int L,int R,int rt 5 #define iall 1,M-1,1 6 #define imid int mid=(L+R)>>1 7 #define lson L,mid,rt<<1 8 #define rson mid+1,R,rt<<1|1 9 typedef __int64 LL; 10 const int M=100010; 11 int tree[M<<2]; 12 int a[M],big[M],sma[M],prebig[M],presma[M]; 13 void pushup(int rt){ 14 tree[rt]=tree[rt<<1]+tree[rt<<1|1]; 15 } 16 void update(int x,lrrt){ 17 if(L==R){ 18 tree[rt]++; 19 return ; 20 } 21 imid; 22 if(mid>=x) update(x,lson); 23 else update(x,rson); 24 pushup(rt); 25 } 26 int query(int x,int y,lrrt){ 27 if(x<=L&&R<=y) return tree[rt]; 28 imid; 29 int ans=0; 30 if(mid>=x) ans+=query(x,y,lson); 31 if(mid<y) ans+=query(x,y,rson); 32 return ans; 33 } 34 int main(){ 35 int t,n; 36 while(~scanf("%d",&t)){ 37 while(t--){ 38 scanf("%d",&n); 39 for(int i=1;i<=n;i++){ 40 scanf("%d",&a[i]); 41 } 42 mt(tree,0); 43 for(int i=n;i>=1;i--){ 44 sma[i]=query(1,a[i],iall); 45 big[i]=n-i-sma[i]; 46 update(a[i],iall); 47 } 48 mt(tree,0); 49 for(int i=1;i<=n;i++){ 50 presma[i]=query(1,a[i],iall); 51 prebig[i]=i-1-presma[i]; 52 update(a[i],iall); 53 } 54 LL ans=0; 55 for(int i=1;i<=n;i++){ 56 ans+=prebig[i]*sma[i]; 57 ans+=presma[i]*big[i]; 58 } 59 printf("%I64d\n",ans); 60 } 61 } 62 return 0; 63 }
A Online Judge http://acm.hdu.edu.cn/showproblem.php?pid=1073
模拟字符串比较
1 #include<cstdio> 2 #include<cstring> 3 const int M=5010; 4 char a[M][M],b[M][M],sa[M*M],sb[M*M],op[M]; 5 bool judge(char c) { 6 if(c==' '||c=='\t'||c=='\n') return false; 7 return true; 8 } 9 int main() { 10 int t; 11 while(~scanf("%d",&t)) { 12 getchar(); 13 while(t--) { 14 gets(op); 15 int la=0; 16 while(gets(op)&&strcmp(op,"END")) { 17 strcpy(a[la++],op); 18 } 19 gets(op); 20 int lb=0; 21 while(gets(op)&&strcmp(op,"END")) { 22 strcpy(b[lb++],op); 23 } 24 if(la==lb) { 25 bool flag=true; 26 for(int i=0; i<la; i++) { 27 if(strcmp(a[i],b[i])) { 28 flag=false; 29 break; 30 } 31 } 32 if(flag) { 33 puts("Accepted"); 34 continue; 35 } 36 } 37 int lsa=0,lsb=0; 38 for(int i=0; i<la; i++) { 39 for(int j=0; a[i][j]; j++) { 40 if(judge(a[i][j])) { 41 sa[lsa++]=a[i][j]; 42 } 43 } 44 } 45 sa[lsa]=0; 46 for(int i=0; i<lb; i++) { 47 for(int j=0; b[i][j]; j++) { 48 if(judge(b[i][j])) { 49 sb[lsb++]=b[i][j]; 50 } 51 } 52 } 53 sb[lsb]=0; 54 if(!strcmp(sa,sb)) puts("Presentation Error"); 55 else puts("Wrong Answer"); 56 } 57 } 58 return 0; 59 }
C Box of Bricks http://poj.org/problem?id=1477
水。
1 #include<cstdio> 2 #include<cstdlib> 3 const int M=1010; 4 int a[M]; 5 int main(){ 6 int n,cas=1; 7 while(~scanf("%d",&n),n){ 8 int sum=0; 9 for(int i=0;i<n;i++){ 10 scanf("%d",&a[i]); 11 sum+=a[i]; 12 } 13 sum/=n; 14 int ans=0; 15 for(int i=0;i<n;i++){ 16 ans+=abs(a[i]-sum); 17 } 18 printf("Set #%d\nThe minimum number of moves is %d.\n\n",cas++,ans/2); 19 } 20 return 0; 21 }
B X问题 http://acm.hdu.edu.cn/showproblem.php?pid=1573
由于x%a=b ai共10个,并且最大值是10,所以最小公倍数最大是2520,可以暴力。
1 #include<cstdio> 2 const int M=16; 3 int a[M],b[M]; 4 int gcd(int a,int b) { //最大公约数 5 return b?gcd(b,a%b):a; 6 } 7 int lcm(int a,int b) { //最小公倍数 8 return a/gcd(a,b)*b; 9 } 10 int main(){ 11 int t,n,m; 12 while(~scanf("%d",&t)){ 13 while(t--){ 14 scanf("%d%d",&n,&m); 15 int sumlcm=1; 16 for(int i=0;i<m;i++){ 17 scanf("%d",&a[i]); 18 sumlcm=lcm(sumlcm,a[i]); 19 } 20 for(int i=0;i<m;i++){ 21 scanf("%d",&b[i]); 22 } 23 int ans=-1; 24 for(int i=1;i<=sumlcm;i++){ 25 bool flag=true; 26 for(int j=0;j<m;j++){ 27 if(i%a[j]!=b[j]){ 28 flag=false; 29 break; 30 } 31 } 32 if(flag){ 33 ans=i; 34 break; 35 } 36 } 37 if(ans==-1||ans>n){ 38 puts("0"); 39 continue; 40 } 41 int sum=(n-ans)/sumlcm+1; 42 printf("%d\n",sum); 43 } 44 } 45 return 0; 46 }
也可以用不要求ai互质的中国剩余定理解模线性方程组。
1 #include<cstdio> 2 const int M=16; 3 int a[M],b[M]; 4 int gcd(int a,int b) { //最大公约数 5 return b?gcd(b,a%b):a; 6 } 7 int lcm(int a,int b) { //最小公倍数 8 return a/gcd(a,b)*b; 9 } 10 int ext_gcd(int a,int b,int &x,int &y) { //扩展gcd d=gcd(a,b)=a*x+b*y; return d,x,y; 11 int t,ret; 12 if(!b) { 13 x=1; 14 y=0; 15 return a; 16 } 17 ret=ext_gcd(b,a%b,x,y); 18 t=x; 19 x=y; 20 y=t-a/b*y; 21 return ret; 22 } 23 int modular_linear_system(int a[],int b[],int n){//求解模线性方程组(无要求)X mod a[i]=b[i],n个方程 24 int m1,m2,r1,r2,c,d,t,x,y; 25 m1=a[0]; 26 r1=b[0]; 27 for(int i=1;i<n;i++){ 28 m2=a[i]; 29 r2=b[i]; 30 c=r2-r1; 31 d=ext_gcd(m1,m2,x,y); 32 if(c%d) return -1; 33 t=m2/d; 34 x=(c/d*x%t+t)%t; 35 r1=m1*x+r1; 36 m1=m1*m2/d; 37 } 38 return r1; 39 } 40 int main() { 41 int t,n,m; 42 while(~scanf("%d",&t)) { 43 while(t--) { 44 scanf("%d%d",&n,&m); 45 int sumlcm=1; 46 for(int i=0; i<m; i++) { 47 scanf("%d",&a[i]); 48 sumlcm=lcm(sumlcm,a[i]); 49 } 50 for(int i=0; i<m; i++) { 51 scanf("%d",&b[i]); 52 } 53 int ans=modular_linear_system(a,b,m); 54 if(ans==-1||ans>n) { 55 puts("0"); 56 continue; 57 } 58 if(ans==0) ans+=sumlcm; 59 int sum=(n-ans)/sumlcm+1; 60 printf("%d\n",sum); 61 } 62 } 63 return 0; 64 }
end