TZOJ 挑战题库随机训练07
A.最小二乘法回到顶部
题意
给个函数,求偏导
题解
高等数学题,过程就不列了,计算可得,复杂度O(1)
k=(Σ(xy)-ΣxΣy/n)/(-(Σx)^2/n+Σ(x^2))
b=(Σy-kΣx)/n
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int n; 6 while(scanf("%d",&n)!=EOF){ 7 double sumx=0,sumx2=0,sumy=0,sumxy=0,x,y; 8 for(int i=1;i<=n;i++){ 9 scanf("%lf%lf",&x,&y); 10 sumx+=x,sumy+=y,sumxy+=x*y,sumx2+=x*x; 11 } 12 double k=(sumxy-sumx*sumy/n)/(-sumx*sumx/n+sumx2); 13 double b=(sumy-k*sumx)/n; 14 printf("%.1f %.1f\n",k,b); 15 } 16 return 0; 17 }
B.Children’s Queue回到顶部
题意
长度为n的序列放0和1,所有的1必须有相邻的1,问方案数,n<=1000
题解
dp[i]表示长度为i的合法方案数
第i个位置放0,那么前i-1个无所谓,dp[i-1]
第i个位置放1,因为要连续,i-1和i-2都放1,dp[i-2]
其实还有一种情况,第i个位置放1,如果前面不合法,放两个1也会导致合法,那么就相当于第i-3放0,i-2放1,相当于不合法,然后放两个连续的1使其合法,就相当于放0111,dp[i-4]
dp[i]=dp[i-1]+dp[i-2]+dp[i-4],复杂度O(1000)
代码
1 import java.math.BigInteger; 2 import java.util.*; 3 4 public class Main { 5 6 public static void main(String[] args) { 7 8 BigInteger[] big = new BigInteger[1005]; 9 big[0] = BigInteger.ONE; 10 big[1] = BigInteger.ONE; 11 big[2] = big[0].add(big[1]); 12 big[3] = big[2].add(big[0].add(big[1])); 13 for(int i = 4; i <= 1000; i++) { 14 big[i] = big[i-1].add(big[i-2].add(big[i-4])); 15 } 16 Scanner sc = new Scanner(System.in); 17 while(sc.hasNext()) { 18 int n = sc.nextInt(); 19 System.out.println(big[n]); 20 } 21 } 22 }
C.Island Transport回到顶部
题意
一张图(u,v,w),从左下开始,到右上,w表示容量,问最多能运多少,N,M<=100000
题解
一看就是网络流,但是N,M这么大怎么办?莽呗,复杂度O(你的模板复杂度)
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 #define INF 0x3f3f3f3f 7 using namespace std; 8 const int maxn=100005; 9 const int maxx=200005; 10 int edge; 11 int to[maxx],flow[maxx],nex[maxx]; 12 int head[maxn]; 13 14 void addEdge(int v,int u,int cap) 15 { 16 to[edge]=u,flow[edge]=cap,nex[edge]=head[v],head[v]=edge++; 17 to[edge]=v,flow[edge]=cap,nex[edge]=head[u],head[u]=edge++; 18 } 19 int vis[maxn]; 20 int pre[maxn]; 21 bool bfs(int s,int e) 22 { 23 queue<int> que; 24 pre[s]=-1; 25 memset(vis,-1,sizeof(vis)); 26 que.push(s); 27 vis[s]=0; 28 while(!que.empty()) 29 { 30 int u=que.front(); 31 que.pop(); 32 for(int i=head[u];~i;i=nex[i]) 33 { 34 int v=to[i]; 35 if(vis[v]==-1&&flow[i]) 36 { 37 vis[v]=vis[u]+1; 38 if(v==e) 39 return true; 40 que.push(v); 41 } 42 43 } 44 } 45 return false; 46 } 47 int dfs(int s,int t,int f) 48 { 49 if(s==t||!f) 50 return f; 51 int r=0; 52 for(int i=head[s];~i;i=nex[i]) 53 { 54 int v=to[i]; 55 if(vis[v]==vis[s]+1&&flow[i]) 56 { 57 int d=dfs(v,t,min(f,flow[i])); 58 if(d>0) 59 { 60 flow[i]-=d; 61 flow[i^1]+=d; 62 r+=d; 63 f-=d; 64 if(!f) 65 break; 66 } 67 } 68 } 69 if(!r) 70 vis[s]=INF; 71 return r; 72 } 73 74 int maxFlow(int s,int e) 75 { 76 int ans=0; 77 while(bfs(s,e)) 78 ans+=dfs(s,e,INF); 79 return ans; 80 } 81 82 void init() 83 { 84 memset(head,-1,sizeof(head)); 85 edge=0; 86 } 87 88 int main(){ 89 int t,x,y,w,n,m,s,e,maxI,minI; 90 scanf("%d",&t); 91 while(t--){ 92 init(); 93 scanf("%d%d%d%d",&n,&m,&x,&y); 94 s=e=1; 95 maxI=minI=x; 96 for(int i=2;i<=n;i++){ 97 scanf("%d%d",&x,&y); 98 if(maxI<x)e=i,maxI=x; 99 if(minI>x)s=i,minI=x; 100 } 101 while(m--){ 102 scanf("%d%d%d",&x,&y,&w); 103 addEdge(x,y,w); 104 } 105 int ans=maxFlow(s,e); 106 printf("%d\n",ans); 107 } 108 return 0; 109 }
D.Problem Bee回到顶部
题意
给俩坐标A和B,蜂巢正六边形,给你个边长d,A要移动到B,如果AB在同一蜂巢直接移动过去,如果在不同蜂巢,A需要移动到中心,每次只能移动到相邻蜂巢,到达B蜂巢中心后再移动到B,蜂巢总中心在(0,0)
题解
数学题,先算出A和B在哪个蜂巢,再计算出需要移动几个蜂巢,最后加上A到中心和B到中心的距离
通过计算可得,x变化量为3d/2,y变化量为sqrt(3)d/2,算出A处在x的第几块,通过奇偶算出A处在y的第几块,然后计算周围的6个蜂巢得到A到底在哪个蜂巢中
同理计算出B,复杂度O(1)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 int dx[]={0,0,1,1,-1,-1}; 4 int dy[]={2,-2,1,-1,1,-1}; 5 double d; 6 void changes(double realx,double realy,double &x1,double &y1){ 7 double minn=(x1-realx)*(x1-realx)+(y1-realy)*(y1-realy); 8 double truex=x1,truey=y1; 9 for(int i=0;i<6;i++){ 10 double rx1=x1+dx[i]*(3*d/2); 11 double ry1=y1+dy[i]*(sqrt(3.0)*d)/2; 12 double val=(rx1-realx)*(rx1-realx)+(ry1-realy)*(ry1-realy); 13 //if(i==3)printf("%.3f %.3f %.3f\n",rx1,ry1,val); 14 if(val<minn){ 15 minn=val; 16 truex=rx1,truey=ry1; 17 } 18 } 19 x1=truex,y1=truey; 20 } 21 int main(){ 22 double x1,y1,x2,y2; 23 while(scanf("%lf%lf%lf%lf%lf",&d,&x1,&y1,&x2,&y2)!=EOF){ 24 //printf("%.3f %.3f %.3f %.3f %.3f\n",d,x1,y1,x2,y2); 25 if(x1==0&&y1==0&&x2==0&&y2==0)break; 26 int b1=x1*2/(3*d),b2=x2*2/(3*d); 27 int e1=y1*2/(d*sqrt(3.0)),e2=y2*2/(d*sqrt(3.0)); 28 if(b1%2==1&&e1%2==0)e1++; 29 else if(b1%2==0&&e1%2==1)e1++; 30 if(b2%2==1&&e2%2==0)e2++; 31 else if(b2%2==0&&e2%2==1)e2++; 32 //printf("%d %d %d %d\n",b1,b2,e1,e2); 33 if(b1==b2&&e1==e2){ 34 printf("%.3f\n",sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))); 35 }else{ 36 double b1x=b1*3*d/2; 37 double b2x=b2*3*d/2; 38 double b1y=e1*sqrt(3.0)*d/2; 39 double b2y=e2*sqrt(3.0)*d/2; 40 changes(x1,y1,b1x,b1y); 41 changes(x2,y2,b2x,b2y); 42 //(b1x,b1y)->(b2x,b2y) 43 //printf("(%.3f,%.3f) (%.3f,%.3f)\n",b1x,b1y,b2x,b2y); 44 int move=fabs(b2x-b1x)*2/(3*d); 45 printf("%.3f\n",move*d*sqrt(3.0)+sqrt((x1-b1x)*(x1-b1x)+(y1-b1y)*(y1-b1y))+sqrt((x2-b2x)*(x2-b2x)+(y2-b2y)*(y2-b2y))); 46 } 47 } 48 return 0; 49 }
E.Tree Recovery回到顶部
题意
给前序中序求后序,n<30
题解
递归建树,dfs(L1,R1,L2,R2)代表前序中的[L1,R1],中序中的[L2,R2]
前序第一个数一定是根,然后在中序中找到根的下标,左右两半分开,复杂度O(n)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n; 5 char s1[30],s2[30]; 6 int dfs(int L1,int R1,int L2,int R2){ 7 if(L1>R1)return 0; 8 char root=s1[L1];int p=L2; 9 while(root!=s2[p])p++; 10 int cnt=p-L2; 11 dfs(L1+1,L1+cnt,L2,p-1); 12 dfs(L1+cnt+1,R1,p+1,R2); 13 printf("%c",root); 14 return root; 15 } 16 int main(){ 17 while(scanf("%s%s",s1,s2)!=EOF){ 18 n=strlen(s1); 19 dfs(0,n-1,0,n-1); 20 printf("\n"); 21 } 22 return 0; 23 }
F.小孩子的扑克牌游戏回到顶部
题意
A和B各有两张扑克,问谁的和离10最近,相同和大的赢
题解
求和判一下绝对值,复杂度O(1)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int a,b,c,d; 6 while(cin>>a>>b>>c>>d){ 7 int e=abs(10-a-b); 8 int f=abs(10-c-d); 9 if(e==f&&a+b==c+d)cout<<"2 2\n"; 10 else if(e<f||a+b<c+d)cout<<"4 0\n"; 11 else cout<<"0 4\n"; 12 } 13 return 0; 14 }
G.The Table回到顶部
题意
n行m列,问哪一列乘积最大,相同输出m大的,n<=1000,m<=20
题解
大数相乘处理一下就行了,复杂度O(nm)
代码
1 import java.math.BigInteger; 2 import java.util.*; 3 4 public class Main { 5 6 public static void main(String[] args) { 7 8 BigInteger[] big = new BigInteger[25]; 9 10 Scanner sc = new Scanner(System.in); 11 while(sc.hasNext()) { 12 int m = sc.nextInt(); 13 int n = sc.nextInt(); 14 BigInteger b; 15 for (int i = 1; i <= m; i++) 16 big[i] = BigInteger.ONE; 17 for (int i = 1; i <= n; i++) { 18 for (int j = 1; j <= m; j++) { 19 b = sc.nextBigInteger(); 20 big[j] = big[j].multiply(b); 21 } 22 } 23 int id = 1; 24 BigInteger maxx = big[1]; 25 for (int i = 2; i <= m; i++) { 26 if (maxx.compareTo(big[i]) <= 0) { 27 maxx = big[i]; 28 id = i; 29 } 30 } 31 System.out.println(id); 32 } 33 } 34 }
H.求和回到顶部
题意
矩阵求和,除去最后一列,最后一行,副对角线,n<=100
题解
两个for,判一下i=n-1,j=n-1,i=n-j+1,复杂度O(n^2)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int n,x; 6 while(cin>>n){ 7 int sum=0; 8 for(int i=1;i<=n;i++) 9 for(int j=1;j<=n;j++){ 10 cin>>x; 11 if(i==n||j==n||i==n-j+1)continue; 12 sum+=x; 13 } 14 cout<<sum<<'\n'; 15 } 16 return 0; 17 }
I.正整数解回到顶部
题意
计算方程x^2+y^2+z^2=num的最小正整数解,num<=10000
题解
100^2=10000,那么直接三个for,复杂度O(<<100^3)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int num,x,y,z; 6 e:while(cin>>num){ 7 for(int i=1;i<=num;i++){ 8 if(i*i>num)break; 9 for(int j=i;j<=num;j++){ 10 if(i*i+j*j>num)break; 11 for(int k=j;k<=num;k++){ 12 if(i*i+j*j+k*k>num)break; 13 if(i*i+j*j+k*k==num){ 14 cout<<i<<" "<<j<<" "<<k<<'\n'; 15 goto e; 16 } 17 } 18 } 19 } 20 } 21 return 0; 22 }
J.Perfect Cubes回到顶部
题意
函数a^3+b^3+c^3=n,求<=n的所有解,n<=100
题解
4个for,10^2=100,复杂度O(n*10^3)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int n,x; 6 while(scanf("%d",&n)!=EOF){ 7 for(int i=6;i<=n;i++){ 8 for(int j=2;j<=n;j++){ 9 if(i*i*i<j*j*j)break; 10 for(int k=j;k<=n;k++){ 11 if(i*i*i<j*j*j+k*k*k)break; 12 for(int l=k;l<=n;l++){ 13 if(i*i*i<j*j*j+k*k*k+l*l*l)break; 14 if(i*i*i==j*j*j+k*k*k+l*l*l){ 15 printf("Cube = %d, Triple = (%d,%d,%d)\n",i,j,k,l); 16 } 17 } 18 } 19 } 20 } 21 } 22 return 0; 23 }